在javascript中,简单的数学运算是,在循环中添加X次数字,得到的结果与之前乘以X然后再添加不同

在javascript中,简单的数学运算是,在循环中添加X次数字,得到的结果与之前乘以X然后再添加不同,javascript,math,Javascript,Math,作为参考,此代码对应。 这是一个简单的购物车/结帐程序,它注册一个项目并将其成本添加到总成本中,它还接受一个项目数量值 注意:我以前读过关于javascript在数学方面的怪异之处的文章,所以我没有感到震惊,但我非常好奇并有兴趣了解在这种特殊情况下的行为,所以也许我会获得一些见解,以便在将来能够防止这种情况发生 所以,我有两个解决方案,第一个是OK-ish,第二个没有问题,我想。这是: 1第一个 独立于第一种方法效率低下的事实(多次检查所有可能的情况并反复添加项目成本)。引起我注意的是返回的额外

作为参考,此代码对应。
这是一个简单的购物车/结帐程序,它注册一个项目并将其成本添加到总成本中,它还接受一个项目数量值

注意:我以前读过关于javascript在数学方面的怪异之处的文章,所以我没有感到震惊,但我非常好奇并有兴趣了解在这种特殊情况下的行为,所以也许我会获得一些见解,以便在将来能够防止这种情况发生

所以,我有两个解决方案,第一个是OK-ish,第二个没有问题,我想。这是:

1第一个
独立于第一种方法效率低下的事实(多次检查所有可能的情况并反复添加项目成本)。引起我注意的是返回的额外十进制值

var cashRegister = {
    total:0,
    add: function(itemCost){
        this.total += itemCost;
    },
    scan: function(item,quantity) {
        for (var i = 1 ; i <= quantity ; i++ ){
            switch (item) {
            case "eggs": this.add(0.98); break;
            case "milk": this.add(1.23); break;
            case "magazine": this.add(4.99); break;
            case "chocolate": this.add(0.45); break;
            }
        }
    }
};

// scan each item 4 times
cashRegister.scan("eggs",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("milk",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("magazine",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("chocolate",4);
console.log('Your bill is '+ cashRegister.total);
第二个
此解决方案将项目数量乘以任何碰巧发生的数量

var cashRegister = {
    total:0,
    add: function(itemCost){
        this.total += itemCost;
    },
    scan: function(item,quantity) {
        switch (item) {
        case "eggs": this.add(0.98*quantity); break;
        case "milk": this.add(1.23*quantity); break;
        case "magazine": this.add(4.99*quantity); break;
        case "chocolate": this.add(0.45*quantity); break;
        }
    }
};

// scan each item 4 times
cashRegister.scan("eggs",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("milk",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("magazine",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("chocolate",4);
console.log('Your bill is '+cashRegister.total);
控制台输出是干净的:

Your bill is 3.92
Your bill is 8.84
Your bill is 28.8
Your bill is 30.6
Your bill is 30.6
那么,第一个解决方案是怎么回事,这样就可以返回小数点排版了?
事先非常感谢

编辑: 谢谢你试图帮助我解决我的疑问。虽然我意识到我需要清楚地表明我知道“JavaScript使用浮点值作为其数字类型,而精度的损失是造成这种情况的原因”

真正的问题是:

为什么相同的计算在第一个解决方案上会丢失精度,而在第二个解决方案上不会丢失精度?

JavaScript使用浮点值作为其
数字类型,精度丢失是导致这种情况的原因。精度损失的原因是,浮点数使用二进制编码格式(很可能),并且它不能精确地表示大多数数字。例如,
0.1
不能在IEEE 754中表示:

  • 十进制:
    0.1
  • 二进制表示:
    0011110111001
  • 十六进制报告。:
    0x3DCCCD
  • 实际值:
    0.1000000149011612
我已经使用了这些结果

所以直接回答你的问题:对浮点数进行更多的运算(多次加法,而不是乘法)会导致错误的积累

一个例子 我最喜欢的精度损失示例之一是以下代码:

var a = 0, b = 0;
for (var i = 1; i < 100; i++) {
    a += Math.pow(10, -9*i);
}
for (var j = 100; j < 1; j--) {
    b += Math.pow(10, -9*i);
}
alert(a == b);
这将产生
“5.57”

ECMAScript标准 根据ECMAScript标准(ECMA-262,版本5.1),数值的定义如下:

与双精度64位二进制格式IEEE 754值相对应的原语值


这就是标准投诉实施为您提供的内容。其他任何可能在后台的内容都是实现细节。

这是由于浮点数固有的不精确性造成的。并非所有有理数都可以用二进制浮点表示为精确值,因此您看到的是这种近似的结果。对如何进行这种转换有很好的解释


如果确实需要精确的值,可以使用或其他类似的库

首先,你为什么要用第一种方法呢?第二,如果你把鸡蛋的价格改为
0.01
,第二种方法给出的最终总价格是
26.720000000000002
。第三,可能对你有帮助……想不想用第一种方式去做,这是无关紧要的。但是谢谢你链接到另一个问题,“不是所有的有理数都可以用浮点表示为精确值”——问题是JS使用二进制浮点。(问题中的所有数字都可以用十进制浮点数精确表示。)我编辑我的问题是为了更好地表达我的问题,谢谢你,兰斯顿我编辑我的问题是为了更好地表达我的问题,谢谢你,梅斯科巴拉兹你添加的示例非常有趣,谢谢你,看来你真的探讨过这个问题,所以我投了赞成票,但它并没有完全回答我的问题,我还不能接受yikes,因为代表率低,所以不能投票,对不起,非常感谢meskobalazs,你的回答对任何在这个问题上发言的人都非常有帮助,这足以接受你的回答,我请我的一个朋友投票支持你。另外,我还猜测javascript虚拟机在加法时的工作方式与乘法时的工作方式非常不同,您对此有进一步的详细信息吗?首先,javascript不是在虚拟机上运行的,而是由javascript引擎运行的。我更新了我的答案,希望它有用。对不起,我是说V8,我用的是chrome。谢谢你提供更多的细节。我可以从这里开始。
var a = 0, b = 0;
for (var i = 1; i < 100; i++) {
    a += Math.pow(10, -9*i);
}
for (var j = 100; j < 1; j--) {
    b += Math.pow(10, -9*i);
}
alert(a == b);
var num = 5.56789;
var n = num.toFixed(2);