Lua:舍入数字,然后截断

Lua:舍入数字,然后截断,lua,rounding,truncate,Lua,Rounding,Truncate,将数字四舍五入,然后将其截断(四舍五入后删除小数点)的最佳有效方法是什么 例如,如果decimal大于0.5(即0.6、0.7等),则我希望进行四舍五入,然后进行截断(情况1)。否则,我将截断(案例2) Lua中没有内置的math.round()函数,但可以执行以下操作: print(math.floor(a+0.5))应该是math.ceil(a-0.5)要正确处理半整数在小数位数(而不是整整数)处进行舍入,一个有用的技巧是通过格式化ASCII文本传递值,并使用%f格式字符串指定所需的舍入。比

将数字四舍五入,然后将其截断(四舍五入后删除小数点)的最佳有效方法是什么

例如,如果decimal大于0.5(即0.6、0.7等),则我希望进行四舍五入,然后进行截断(情况1)。否则,我将截断(案例2)


Lua中没有内置的math.round()函数,但可以执行以下操作:
print(math.floor(a+0.5))
应该是
math.ceil(a-0.5)
要正确处理半整数

在小数位数(而不是整整数)处进行舍入,一个有用的技巧是通过格式化ASCII文本传递值,并使用
%f
格式字符串指定所需的舍入。比如说

mils = tonumber(string.format("%.3f", exact))
exact
中的任意值四舍五入为0.001的倍数

在使用
math.floor()
math.ceil()
中的一种之前和之后,缩放也会产生类似的结果,但是根据您对边缘情况处理的期望,正确获取细节可能会很棘手。并不是说这不是
string.format()
的问题,而是为了使它产生“预期”的结果,做了大量的工作

四舍五入到十次方以外的倍数仍然需要缩放,并且仍然存在所有棘手的边缘情况。一种易于表达且行为稳定的方法是编写

function round(exact, quantum)
    local quant,frac = math.modf(exact/quantum)
    return quantum * (quant + (frac > 0.5 and 1 or 0))
end

并调整
frac
(可能还有
exact
的符号)上的精确条件,以获得所需的边缘情况。

要同时支持负数,请使用以下命令:

function round(x)
  return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
对于不正确的舍入(切割末端):

如果你想的话,你可以把它展开,好的四舍五入

function round(number)
  if (number - (number % 0.1)) - (number - (number % 1)) < 0.5 then
    number = number - (number % 1)
  else
    number = (number - (number % 1)) + 1
  end
 return number
end

print(round(3.1))
print(round(math.pi))
print(round(42))
print(round(4.5))
print(round(4.6))
函数舍入(数字)
如果(编号-(编号%0.1))-(编号-(编号%1))<0.5,则
编号=编号-(编号%1)
其他的
编号=(编号-(编号%1))+1
结束
返回号码
结束
印刷品(圆形(3.1))
打印(圆形(数学圆周率))
印刷品(第42轮)
印刷品(圆形(4.5))
印刷品(圆形(4.6))
预期成果:


3
3
42
5
5
这里有一个四舍五入到任意位数(如果未定义,则为0):


我喜欢上面RBerteig的回答:
mils=tonumber(string.format(“%.3f”,精确))
。 将其扩展为函数调用并添加精度值

function round(number, precision)
   local fmtStr = string.format('%%0.%sf',precision)
   number = string.format(fmtStr,number)
   return number
end

如果您的Lua像大多数人一样使用双精度IEC-559(又称IEEE-754)浮点,并且您的数字相对较小(该方法保证适用于-251和251之间的输入),则以下高效代码将使用FPU的当前舍入模式执行舍入,该模式通常是舍入到最近,甚至是偶数:

local function round(num)
  return num + (2^52 + 2^51) - (2^52 + 2^51)
end
(请注意,括号中的数字是在编译时计算的;它们不会影响运行时)

例如,当FPU设置为四舍五入到最近或偶数时,此单元测试打印“所有测试通过”:

下面是另一个(当然效率较低)算法,它执行相同的FPU舍入,但适用于所有数字:

local function round(num)
  local ofs = 2^52
  if math.abs(num) > ofs then
    return num
  end
  return num < 0 and num - ofs + ofs or num + ofs - ofs
end
局部函数舍入(num)
本地ofs=2^52
如果math.abs(num)>ofs那么
返回数
结束
返回num<0和num-ofs+ofs或num+ofs-ofs
结束

这是一个灵活的函数,可以四舍五入到不同的位置。我用负数、大数、小数和各种边缘情况对它进行了测试,它是有用和可靠的:

function Round(num, dp)
    --[[
    round a number to so-many decimal of places, which can be negative, 
    e.g. -1 places rounds to 10's,  
    
    examples
        173.2562 rounded to 0 dps is 173.0
        173.2562 rounded to 2 dps is 173.26
        173.2562 rounded to -1 dps is 170.0
    ]]--
    local mult = 10^(dp or 0)
    return math.floor(num * mult + 0.5)/mult
end
function round(number, decimals)
  local scale = 10^decimals
  local c = 2^52 + 2^51
  return ((number * scale + c ) - c) / scale
end

对于四舍五入到给定数量的小数(也可以是负数),我建议结合已经作为答案呈现的结果,特别是。我测试了几个我感兴趣的角落案例,但不能说这使该功能100%可靠:

function Round(num, dp)
    --[[
    round a number to so-many decimal of places, which can be negative, 
    e.g. -1 places rounds to 10's,  
    
    examples
        173.2562 rounded to 0 dps is 173.0
        173.2562 rounded to 2 dps is 173.26
        173.2562 rounded to -1 dps is 170.0
    ]]--
    local mult = 10^(dp or 0)
    return math.floor(num * mult + 0.5)/mult
end
function round(number, decimals)
  local scale = 10^decimals
  local c = 2^52 + 2^51
  return ((number * scale + c ) - c) / scale
end
这些情况说明了“一半到一半”属性(在大多数机器上应为默认值):


我知道我的回答没有处理实际问题的第三种情况,但为了符合IEEE-754标准,我的方法是有意义的。因此,我希望结果取决于FPU中设置的当前舍入模式。这就是为什么在将
FE\u设置为零后(在Lua中可以这样做),这个解决方案很可能会返回问题中要求的结果。

取决于“正确”的含义。一个人必须仔细地决定关于半步该做什么,以及如何处理负值。加一半和
floor
,减去一半和
ceil
这两种方法都会对精确的一半产生一致的偏差。这两种方法都不同于加法半和截断,假设截断通常向零舍入。从某种意义上说,实施从圆到平的价值更“公平”。四舍五入充满了微妙之处。
a
应该是什么?@averwhy
a
是您要四舍五入的值。对于a=0.49999999994,返回1;它应该返回0。@PedroGimeno这是唯一的错误案例,还是还有其他错误案例?我尝试了
1.49999999988+0.5
,效果很好。同样适用于
2.49999999977+0.5
@RolandIllig这是我所知的唯一情况。由于四舍五入,0.49999999994和0.5相加返回1;对于较大的数字,舍入不会导致问题,因为它们没有足够的有效数字来影响舍入。这个数字很特别,因为0.5比它大。不幸的是,
string.format()。当面对“精确”的一半时,请查看哪个更喜欢向上取整,而其他大多数取整。不幸的是
string.format()
取整方式因使用的Lua版本而异。当面对“精确”的一半时,看看哪一个更喜欢向上取整,而其他大多数取整。这对Lua有效,但对LuaJIT无效。如果你让
x=32.90625
n=4
那么大多数Luas会给你
32.9062
,但LuaJIT会给你
23.0963
function Round(num, dp)
    --[[
    round a number to so-many decimal of places, which can be negative, 
    e.g. -1 places rounds to 10's,  
    
    examples
        173.2562 rounded to 0 dps is 173.0
        173.2562 rounded to 2 dps is 173.26
        173.2562 rounded to -1 dps is 170.0
    ]]--
    local mult = 10^(dp or 0)
    return math.floor(num * mult + 0.5)/mult
end
function round(number, decimals)
  local scale = 10^decimals
  local c = 2^52 + 2^51
  return ((number * scale + c ) - c) / scale
end
assert(round(0.5, 0) == 0)
assert(round(-0.5, 0) == 0)
assert(round(1.5, 0) == 2)
assert(round(-1.5, 0) == -2)
assert(round(0.05, 1) == 0)
assert(round(-0.05, 1) == 0)
assert(round(0.15, 1) == 0.2)
assert(round(-0.15, 1) == -0.2)