JavaScript 添加十进制数字问题

IT技术 javascript numbers
2021-02-27 20:25:18

所以我正在制作一个将两个数字(十进制数字)相加的脚本,我遇到了一个问题。

http://jsfiddle.net/DerekL/esqnC/

我编写了脚本,结果非常好:

0.1 + 0.5  //0.6
0.2 + 0.3  //0.5

但很快我就看到:

0.1 + 0.2  //0.30000000000000004
0.01 + 0.06  //0.06999999999999999

而且在我看来并不合适。我知道使用带有有限位的浮点数是一个缺点,但我找不到解决这个问题的方法。

Math.ceil   //No
Math.floor  //No
.slice      //No

更新

是否可以先将数字乘以 1000,然后将它们相加然后除以 1000?

4个回答

使用toFixed将其转换为与剃掉了一些小数位的字符串,然后将其转换回数字。

+(0.1 + 0.2).toFixed(12) // 0.3

看起来 IEtoFixed有一些奇怪的行为,所以如果你需要支持 IE,这样的东西可能会更好:

Math.round((0.1 + 0.2) * 1e12) / 1e12
@Derek 在阅读了关于作为重复链接的问题的一些评论后,看起来 IE 的 toFixed 可能会截断而不是圆形。做这样的事情可能更安全:Math.round((0.1 + 0.2) * 1e12) / 1e12
2021-04-30 20:25:18
@GGG:可能吧。toFixed无论如何,您的解决方案在这里有效:jsfiddle.net/KooiInc/D7ULx
2021-05-08 20:25:18
不错,有效:jsfiddle.net/esqnC/5
2021-05-11 20:25:18
@GGG - 看起来这是最终的解决方法。谢谢!
2021-05-16 20:25:18
@GGGMath.round()是个好主意 :)
2021-05-18 20:25:18
function add(){
    var first=parseFloat($("#first").val());
    var second=parseFloat($("#second").val());
    $("#result").val(+(first+second).toFixed(2));
}

演示。

parseFloat(11200030006000.126) 仍然是 11200030006000.127
2021-05-10 20:25:18

这是浮点的常见问题。

使用toFixed与组合parseFloat

这是JavaScript 中的示例

function roundNumber(number, decimals) {
    var newnumber = new Number(number+'').toFixed(parseInt(decimals));
    return parseFloat(newnumber); 
}

0.1 + 0.2;                    //=> 0.30000000000000004
roundNumber( 0.1 + 0.2, 12 ); //=> 0.3
这确实很奇怪。我还尝试了 GGG 的解决方案(jsfiddle.net/49HGP/6),它的计算结果也为 11200030006000.127。你知道为什么会发生这种情况吗?
2021-04-21 20:25:18
但现在的结果是:11200030006000.125 + 0.001 = 11200030006000.127应该是 11200030006000.126 ...
2021-05-05 20:25:18
用 11200030006000.125 + 0.001 试试
2021-05-09 20:25:18
您是对的,KooiInc 和我将其更新为 12 位精度。GGG 的 Math.round((0.1 + 0.2) * 1e12) / 1e12 的解决方案仍然是优雅的解决方案!
2021-05-11 20:25:18
对于这么大的数字,我认为这只是精度问题,而不是二进制重复小数。 10000000000000.126 == 10000000000000.127 // true
2021-05-11 20:25:18

测试这个 Javascript:

var arr = [1234563995.721, 12345691212.718, 1234568421.5891, 12345677093.49284];

var sum = 0;
for( var i = 0; i < arr.length; i++ ) {
    sum += arr[i];
}

alert( "fMath(sum) = " + Math.round( sum * 1e12 ) / 1e12 );
alert( "fFixed(sum) = " + sum.toFixed( 5 ) );

结论

不要使用 Math.round( (## + ## + ... + ##) * 1e12) / 1e12

相反,使用 ( ## + ## + ... + ##).toFixed(5) )

在 IE 9 中,toFixed效果很好。

new Number((11200030006000.125 + 0.001).toFixed(5)) 仍然 = 11200030006000.127,但如果你把它留成一个字符串 (11200030006000.125 + 0.001)0.001)0.001.0201020100x30001020010201000003001020102010000030006000.127。四舍五入。这仍然是一个奇怪的问题,您必须真正对小数位做出假设。仍在寻找准确的解决方案 我不必担心
2021-04-22 20:25:18
你的结论是什么?
2021-04-26 20:25:18
请举例说明结果,或者至少创建一个小提琴
2021-05-19 20:25:18