Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/476.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么Math.cbrt(1728)比Math.pow(1728,1/3)产生更精确的结果?_Javascript_Floating Point - Fatal编程技术网

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

Javascript 为什么Math.cbrt(1728)比Math.pow(1728,1/3)产生更精确的结果?,javascript,floating-point,Javascript,Floating Point,在JavaScript中,Math.cbrt(1728)计算出12的精确结果 然而,看似等价的表达式Math.pow(1728,1/3)的计算结果为11.999999999998 为什么这些结果在精度上有所不同?前面有几点概述: 如本文所述, 由于有限精度和范围限制,浮点运算 与真实的数学有很大的不同(例如 数学上等价的表达式不是 在浮点运算中求值时必须相等 计算机语言标准通常不保证任何 数学函数的特定精度,或相同的误差范围 在不同的数学函数之间,例如cbrt()或pow()。但是 数学库,为给

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

然而,看似等价的表达式
Math.pow(1728,1/3)
的计算结果为
11.999999999998


为什么这些结果在精度上有所不同?

前面有几点概述:

  • 如本文所述, 由于有限精度和范围限制,浮点运算 与真实的数学有很大的不同(例如 数学上等价的表达式不是 在浮点运算中求值时必须相等

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

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

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

    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()
    的结果比来自
    cbrt()
    的结果小一个。对于数量级较大的参数,差异将大得多。例如,如果
    x
    为21022,则相应的结果相差94 ulps:

    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)
    ,而是使用替代计算方案。虽然实现方式会有所不同,但常用的方法是从初始低精度近似开始,然后是一个或多个具有立方收敛性的步骤


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

    此问题可能是重复的,但它似乎不是链接问题的重复。1.0/3.0不能准确地表示为浮点数,这意味着
    pow()
    的输入有错误。幂运算具有放大输入误差的众所周知的特性(即,输出误差大于输入误差)。假设
    cbrt()
    pow()
    都是以类似的最大误差(通常是高质量数学库的情况)实现的,那么
    pow(x,1.0/3.0)
    的计算精度就不如
    cbrt(x)
    。后者通常也会更快。事实上,由于我在前面的评论中指出的问题,一个双精度数学库正确地舍入
    cbrt()
    pow()
    将返回问题中所述的精确结果:
    cbrt(1728)=1.20000000000e+001 0x1.80000000000p+3;战俘(1728,1.0/3.0)=1.199999999998E+001 0x1.7ffffffffffffp+3
    @地毯烟民
    无理数是任何不能表示为整数比率的实数
    两个数字都不是无理数。@LyingOnTheSky:该链接仅指如何添加类似于
    Math.cbrt
    的内容(如果无法从实施本机版本使用了一个不同的函数,该函数应该比简单地执行
    Math.pow(x,1/3)
    更精确。相关问题:您是如何在5分钟内编写此函数的?!你有那种脑-键盘接口吗?@lxg:我没有。在过去的五分钟里,我一直在申请一些小的修正。但是我花了20多分钟才写出来。啊,是我的错……我误解了“xx分钟前回答的”。我需要更多的咖啡。无论如何,大约20分钟仍然令人印象深刻@lxg:我的专业背景包括微处理器浮点单元和数学库的设计,另外,当我要求重新打开问题时,我已经知道我想写什么了。