为什么改变求和的顺序会得到不同的结果
在数学中,加法具有结合性质。结合律指出,无论加数的顺序如何,求和的结果都保持不变。当加数为整数时,所有的编程语言都遵循这个规则。然而,当加数为浮点数时,行为会稍有不同。
今天大多数使用的CPU都采用IEEE 754二进制浮点标准,该标准在将十进制数存储为二进制值时引入了一些不准确性。当我们改变顺序时,观察到求和结果的变化是因为存储在内存中的中间值也会发生变化,从而导致最终结果也发生变化。让我们来看下面的示例,展示了在改变顺序时如何获得不同的输出。
示例:
var a = 10.54;
var b = 9.99;
var c = 1.01;
console.log("a+b+c", a+b+c);
console.log("b+c+a", b+c+a);
console.log("b+a+c", b+a+c);
输出:
a+b+c 21.540000000000003
b+c+a 21.54
b+a+c 21.540000000000003
解决方案: 解决这个问题的方法是使用 BigDecimal 类。这个JavaScript类表示任意精度的浮点数。在数学运算中,BigDecimal类会将浮点数四舍五入,以确保改变顺序不会改变结果。需要使用 required 函数将这个包导入到程序中。
这个包可以使用以下 npm 命令来安装。
npm install js-big-decimal
方法1
该包含有内建的 add() 方法,它接受两个字符串参数,将它们相加并返回结果的四舍五入值。这可以用于正确地相加多个数字。
示例: 这个示例展示了上述方法。
var bigDecimal = require('js-big-decimal');
var a = "10.54";
var b = "9.99";
var c = "1.01";
console.log("a = ", a);
console.log("b = ", b);
console.log("c = ", c);
var ab = "" + bigDecimal.add(a, b);
var abc = bigDecimal.add(ab, c);
console.log("a+b+c = ", abc);
var bc = "" + bigDecimal.add(b, c);
var bca = bigDecimal.add(bc, a);
console.log("b+c+a = ", bca);
var ba = "" + bigDecimal.add(b, a);
var bac = bigDecimal.add(ba, c);
console.log("b+a+c = ", bac);
输出:
a = 10.54
b = 9.99
c = 1.01
a+b+c = 21.54
b+c+a = 21.54
b+a+c = 21.54
方法2
另一种方法是使用BigDecimal类的实例属性。使用new操作符创建BigDecimal数字的实例。add()方法调用一个实例,并以另一个实例作为参数。第二个add()方法由第一个add()方法返回的结果调用。最后,使用getValue()方法获取BigDecimal数字的字符串值。观察到,所有三种数字排列的相加结果都是相同的。
示例: 该示例展示了上述方法。
var bigDecimal = require('js-big-decimal');
var a = new bigDecimal("10.54");
var b = new bigDecimal("9.99");
var c = new bigDecimal("1.01");
var abc = (a.add(b).add(c)).getValue();
var bca = (b.add(c).add(a)).getValue();
var bac = (b.add(a).add(c)).getValue();
console.log("a+b+c = ", abc);
console.log("b+c+a = ", bca);
console.log("b+a+c = ", bac);
输出:
a+b+c = 21.54
b+c+a = 21.54
b+a+c = 21.54