gpt4 book ai didi

javascript - 为什么 Math.cbrt(1728) 产生的结果比 Math.pow(1728, 1/3) 更准确?

转载 作者:可可西里 更新时间:2023-11-01 02:04:09 57 4
gpt4 key购买 nike

在 JavaScript 中,Math.cbrt(1728) 计算出 12 的精确结果。

但是,看似等价的表达式 Math.pow(1728, 1/3) 的计算结果为 11.999999999999998

为什么这些结果的精度不同?

最佳答案

前面的一些一般性评论:

  1. 如本 seminalpaper 中所述,由于有限的精度和范围限制,浮点运算与真正的数学完全不同(例如,缺乏结合性)数学上等价的表达式不是在浮点运算中计算时必然等效。

  2. 计算机语言标准通常不保证任何数学函数的特定精度,或相同的误差范围在不同的数学函数之间,例如 cbrt()pow()。但为给定的提供正确四舍五入结果的数学库精度确实存在,例如 CRlibm .

然而,在这种情况下,cbrt(x) 将提供比 pow(x,1.0/3.0) 更准确的结果,即使两个函数都针对所有输入正确舍入.

问题是 1.0/3.0 不能精确表示为 float ,无论是二进制还是十进制。最接近三分之一的 IEEE-754 double 是 3.3333333333333331e-1(或 0x1.555555555555p-2,当以 C/C++ 十六进制浮点格式表示时)。相对表示误差为 -5.5511151231257827e-17 (-0x1.0000000000000p-54),这意味着 1/3 的最佳 double 表示略小于所需的数学值。

pow() 的输入之一中的初始误差不仅传递到输出,而且由于求幂的误差放大特性而被放大。因此,pow(x,1.0/3.0) 通常会提供与所需的立方根相比太小的结果,即使 pow() 提供正确舍入的结果也是如此.对于问题中的示例,正​​确舍入的结果是

cbrt(1728.0)        = 1.2000000000000000e+1  (0x1.8000000000000p+3)
pow(1728.0,1.0/3.0) = 1.1999999999999998e+1 (0x1.7ffffffffffffp+3)

也就是说,pow() 的结果是一个 ulp小于 cbrt() 的结果。对于量级较大的论点,差异会大得多。例如,如果 x 为 21022,则各自的结果相差 94 ulp:

x              = 4.4942328371557898e+307  (0x1.0000000000000p+1022)
cbrt(x) = 3.5553731598732904e+102 (0x1.965fea53d6e3dp+340)
pow(x,1.0/3.0) = 3.5553731598732436e+102 (0x1.965fea53d6ddfp+340)

本例中pow()的结果相对误差为1.3108e-14,说明上述相对误差的放大倍数。

出于准确性和性能的原因,实现 cbrt() 的数学库因此通常不会将 cbrt(x) 映射到 pow(x,1.0/3.0) 但使用替代计算方案。虽然实现会有所不同,但常用的方法是从初始低精度近似开始,然后是一个或多个步骤 Halley's method具有三次收敛性。

根据经验,当一种计算机语言同时提供专用立方根功能和一般求幂功能时,对于立方根的计算,前者应该优先于后者。

关于javascript - 为什么 Math.cbrt(1728) 产生的结果比 Math.pow(1728, 1/3) 更准确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26951407/

57 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com