![](/img/trans.png)
[英]JS floating point causing incorrect rounding - Math.round() always works?
[英]JS floating point causing incorrect rounding
我有可能是一个极端情况。 当尝试将值4.015
到小数点后4.015
,我总是以4.01
结尾,而不是期望的4.02
。 对于以.015
为小数部分的所有数字,都会发生这种情况。
我在JS中使用一种相当普通的方法进行处理:
val = Math.round(val * 100) / 100;
我认为问题是乘以100时开始的。浮点数不准确导致此值四舍五入而不是向上取整。
var a = 4.015, // 4.015
mult = a * 100, // 401.49999999999994 (the issue)
round = Math.round(mult), // 401
result = round / 100; // 4.01 (expected 4.02)
小提琴: http : //jsfiddle.net/eVXRL/
如果我尝试舍入为4.025
则不会发生此问题。 确实返回了4.03
的期望值; 到目前为止,这只是.015
的问题。
有没有办法优雅地解决这个问题? 当然,只是寻找.015
并一次性处理该案例是很.015
,但这似乎是错误的!
浮点数不是实数 ,而是浮点数。
实数是无限的,但是只能用有限的位数来表示它们,因此有时,如果所需的确切数不能在浮点系统中表示,则必须存在一些舍入误差。
因此,在处理浮点数时,必须考虑到的是,您不会想到完全相同的数字。
如果您需要一个确切的数字,则应该使用一个可以提供更高精度的库,通常它将使用定点和/或符号表示法
有关更多信息,请参见Wikipedia分页以及此文章(有点复杂,但很重要): 每位计算机科学家应了解的浮点运算法则
我最终使用math.js进行数学运算,从而解决了我所有的浮点问题。
该lib的优点在于,无需实例化任何类型的Big Decimal对象(即使该lib确实支持BigDecimal)。 这只是简单的更换Math
与math
和传球的精度。
如果要使用数字作为小数,请使用十进制库,例如big.js。
大多数语言(包括javascript)中的浮点值都以二进制表示形式存储。 通常,这就是您期望的。 在这种情况下,您的4.015将转换为二进制字符串,并且碰巧被编码为您看到的4.014999999 ...值,这是双精度(8字节)IEEE754值中可用的最接近的二进制表示形式。
如果您正在做金融数学或人类消费数学(即小数),那么您将需要4.015舍入到4.02,并且需要一个十进制库。
由于新的IEEE754-2008标准包括decimal32等作为十进制浮点值表示形式,因此计划在javascript中包含浮点值的十进制表示形式(例如here )。 有关更多信息,请参见: http : //speleotrove.com/decimal/
最后,如果您使用javascript进行会计数学运算(即不应意外产生或消失金钱的财务计算),则请以整分/便士进行所有计算。
您可以使用正则表达式提取并替换数字以获得所需的内容:
val = (val + "").replace(/^([0-9]+\.[0-9])([0-9])([0-9]).*$/, function(whole, head, lastdigit, followup) {
if(followup >= 5) {
return head + ("" + (parseInt(lastdigit) + 1));
}else return head + lastdigit;
});
否则,您可以使用val = val.toFixed(2)
但特定的值4.015给出4.01(4.0151给出4.02作为“预期”)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.