当我运行下面的简单计算时,Chrome和Firefox上的结果略有不同。
铬:56.1124478168614
Firefox:56.11244781686139
let x = -24.42;
let y = -50.519999999999925;
console.log(Math.hypot(x, y));
Math.hypot()
的规范中是否存在漏洞,或者其中一个浏览器以错误的方式实现了它?
编辑:在Firefox中,Math.hypot(x, y)
给出的结果与Math.sqrt(x*x, y*y)
相同,而在Chrome中,与Math.hypot(x, y)
的结果略有不同。因此,我怀疑Firefox的计算是正确的。
尽管Math.js
在两种浏览器中是相同的代码,但不同的引擎有不同的算法来执行基本运算。例如,有许多不同的计算平方根的方法,两个不同的引擎不太可能共享完全相同的实现
有人努力使发动机的精度标准化,但迄今为止尚未成功。例如,请参阅本文
至于为什么Chrome中的Math.hypot
会返回不同的值来在同一个引擎中手动进行计算,Math.hypot
是一种有效的近似值,而不仅仅是一种将工作打包为单个函数的巧妙方法。因此,根据实施方式,其结果可能与实际计算不同。您正确地指出,在这种情况下,Firefox具有更精确的数字实现,您的简单测试就证明了这一点。
在Firefox中,
Math.hypot(x, y)
给出与Math.sqrt(x*x, y*y)
相同的结果
这让我们对Firefox如何实现Math.hypot
:-(做出了相当有把握的猜测
在Chrome中,
Math.hypot(x, y)
的结果与略有不同
以下是Chrome的实现:
https://chromium.googlesource.com/v8/v8/+/master/src/builtins/math.tq#389
正如您从第421行的注释中看到的,Kahan求和用于避免/最小化舍入误差——因此,显然其目的是使比简单的sqrt(x*x + y*y)
实现更准确。(我试图验证在这种情况下是否真的是这样的结果,但Wolfram Alpha只是四舍五入到56.1124
,我不知道还有什么方便的无限精度浮点计算器,所以我不能肯定。(
正确计算
在存在有限精度和舍入误差的情况下;正确的";这种方式很难定义。例如,在某些情况下,(数学等效!(表达式(a * b) / c
和a * (b / c)
由于舍入而产生不同的结果,更重要的是,其中a、b、c的值决定了计算结果的哪种方式更接近(无限精度(理论结果,因此每个实现都可以得到";幸运的";或";不幸";。