繁体   English   中英

JS浮点导致舍入不正确

[英]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)。 这只是简单的更换Mathmath和传球的精度。

如果要使用数字作为小数,请使用十进制库,例如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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM