0

当我在下面运行简单计算时,Chrome 和 Firefox 上的结果略有不同。

铬合金:56.1124478168614

火狐:56.11244781686139

let x = -24.42;
let y = -50.519999999999925;
console.log(Math.hypot(x, y));

规范中是否存在漏洞,Math.hypot()或者其中一个浏览器以错误的方式实现它?

编辑:在 FirefoxMath.hypot(x, y)中给出的结果与Math.sqrt(x*x, y*y)在 Chrome 中的结果Math.hypot(x, y)略有不同。因此我怀疑 Firefox 正在正确地进行计算。

4

2 回答 2

1

在 FirefoxMath.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) / ca * (b / c)产生不同的结果,更重要的是,a、b、c 的值决定了哪种计算结果的方式更接近(无限精度) ) 理论结果,因此每个实现都可能得到“幸运”或“不幸”。

于 2020-07-16T10:26:12.320 回答
1

尽管Math.js两种浏览器中的代码相同,但不同的引擎具有不同的算法来执行基本算术。例如,计算平方根有许多不同的方法,两个不同的引擎不太可能共享完全相同的实现。
有努力标准化跨引擎的精度,但它们尚未成功。例如,请参阅这篇文章
至于为什么Math.hypot在 Chrome 中会返回不同的值来在同一引擎中手动进行计算,Math.hypot旨在作为一种有效的近似 - 不仅仅是将工作包装成单个函数的简洁方式。因此,根据实施情况,其结果可能与实际计算有所不同。您说得对,在这种情况下,Firefox 的实现在数值上更准确,正如您的简单测试所证明的那样。

于 2020-07-16T10:18:13.850 回答