我有两个数字需要进行比较。下面这个例子中的数字是在两个不同系统中计算 26^26
的结果,其中之一是我的javascript代码。
然而,当我比较这两个数字时,得到的结果如下:
AssertionError [ERR_ASSERTION]: 4.0329146112660565e+26 == 4.0329146112661e+26
显然它们不相等,但从理论上讲它们应该相等。
在JavaScript中,对于大数进行相等比较,应该使用何种正确方法(即使这只是一个近似值)?
我有两个数字需要进行比较。下面这个例子中的数字是在两个不同系统中计算 26^26
的结果,其中之一是我的javascript代码。
然而,当我比较这两个数字时,得到的结果如下:
AssertionError [ERR_ASSERTION]: 4.0329146112660565e+26 == 4.0329146112661e+26
显然它们不相等,但从理论上讲它们应该相等。
在JavaScript中,对于大数进行相等比较,应该使用何种正确方法(即使这只是一个近似值)?
更新: 如果你的目标引擎是 es2020
或更高版本, 你可以使用新的 BigInt
JavaScript 基元,用于表示大于 Number.MAX_SAFE_INTEGER
的数字。
BigInt(4.0329146112660565e+26) === BigInt(4.0329146112661e+26)
//false
Math.abs(4.0329146112660565e+26 - 4.0329146112661e+26) === 4329327034368
4329327034368 / 4.0329146112660565e+26 === 1.0734983136696987e-14
看起来这是一个相当小的数字。如果您使用一堆值重复执行同样的操作,您应该能够确定您想要的误差范围。然后,您只需要对任意数字执行相同的操作,看看是否 "差异比率" 对您来说足够小。
function similar(a, b) {
let diff = Math.abs(a - b);
let smallest = Math.min(Math.abs(a), Math.abs(b));
let ratio = diff / smallest;
return ratio < MARGIN_OF_ERROR;
}
我刚刚想出了一种确定两个数字之间差异重要性的方法。这可能不是一个非常聪明的计算方法,它可能适用于某些情况而不适用于其他情况。但是总体思路是你需要编写一个函数来确定两个值是否足够接近,并使用自己定义的“接近”概念。
请注意,JavaScript 是你进行数学计算时最糟糕的语言之一。当整数超过 Number.MAX_SAFE_INT (似乎根据 Chrome 的说法为9007199254740991,不确定在其他浏览器中是否有所不同或是否为标准化常量) 时,它们会变得不精确。
var a = 4.0329146112660565e+26;
var b = 4.0329146112661e+26;
a = Math.round(a/10e+20)*10e+20
b = Math.round(b/10e+20)*10e+20
a == b;
10e+20
似乎是一个有点神奇的数字。你介意解释一下它背后的逻辑吗? 这个解决方案与 @GitaarLAB 关于 Number.MAX_SAFE_INTEGER
的建议相结合,对我很有用。Math.round(4.0329146112661e+26 / Number.MAX_SAFE_INTEGER) * Number.MAX_SAFE_INTEGER;
- Waseem20
和 26
转换为数字,它们已经是数字了:10e+20 == 10e20
。 - dandavis我建议使用一个大数库:
例子:
var x = new Big('4.0329146112660565e+26');
var y = new Big('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.eq(y));
示例:
var x = bn.of('4.0329146112660565e+26');
var y = bn.of('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.equals(y));