浮点倒数总是往返吗?

时间:2017-06-19 06:11:35

标签: floating-point precision floating-accuracy ieee-754

对于IEEE-754算术,倒数的最后位置精度是否保证0或1个单位?从那开始,是否有一个保证的误差限制在倒数的倒数上?

1 个答案:

答案 0 :(得分:9)

[以下所有内容均采用固定的IEEE 754二进制格式,并采用某种形式的舍入模式作为舍入模式。]

由于倒数(计算为1/x)是一个基本的算术运算,1是完全可表示的,并且算术运算保证由标准正确舍入,相互结果保证在{ {1}}单位在真值的最后一个位置。 (这适用于标准中指定的基本算术运算的任何。)

一般来说,值0.5的倒数的倒数不能保证等于x。 IEEE 754 binary64格式的快速示例:

x

但是,假设避免溢出和下溢,并且>>> x = 1.8 >>> 1.0 / (1.0 / x) 1.7999999999999998 >>> x == 1.0 / (1.0 / x) False 是有限的,非零的,并且可以精确表示,则以下结果是正确的:

  1. x的值与1.0 / (1.0 / x)的值相差不超过最后一个单位。

  2. 如果x的有效位数(通常标准化为x范围内)小于[1.0, 2.0),那么倒数 往返:sqrt(2)

  3. 证明草图:在不失一般性的情况下,我们可以假设1.0 / (1.0 / x) == x为正,并将x缩放为2的幂,使其位于x范围内。在[1.0, 2.0)是2的精确幂的情况下,上述结果显然是正确的,所以我们假设它不是(这将在下面的第二步中有用)。下面的证明是针对IEEE 754 binary64格式的特定精度给出的,但它直接适应任何IEEE 754二进制格式。

    在舍入之前,将x写为倒数的 true 值,并让1 / x成为(唯一的,事实证明)最接近的可表示的binary64 float to { {1}}。然后:

    • 因为y是距离1 / x最近的浮点数,y1 / x都位于binade y中,其间的间距为1/x连续的浮点数恰好是[0.5, 1.0],我们有2^-53。事实上,我们可以做得更好:

    • 我们实际上有一个严格的不平等:|y - 1/x| <= 2^-54。如果|y - 1/x| < 2^-54 完全等于|y - 1/x|,则2^-54将在任意精度二进制浮点中完全表示(因为1/xy是)。但是唯一的2^-54二进制浮点x在某种程度上可以精确表示,是2的幂,我们已经排除了这种情况。

    • 如果1/x然后x < sqrt(2),因此(将两者四舍五入到最近的可表示的浮点数),我们有1 / x > x / 2,所以y >= x / 2

      < / LI>
    • 现在x / y <= 2,以及x - 1/y = (y - 1/x) x/y|y - 1/x|上的界限(仍然假设x/y)我们得到x < sqrt(2)。因此,|x - 1/y| < 2^-53是距离x最近的可表示浮点数,1/y1/y舍入并且往返成功。这样就完成了第2部分的证明。

    • 在一般情况x中,我们有x < 2,因此x / y < 4。这使得|x - 1/y| < 2^-52距离1/y最多1 ulp,这样就完成了第1部分的证明。

    这里是x阈值的演示:使用Python,我们在sqrt(2)范围内采用了一百万个随机浮点数,并识别那些不通过倒数往返的浮点数。所有小于[1.0, 2.0)的样本都会通过往返。

    sqrt(2)

    并且证明最大误差不超过1 ulp,一般来说(对于binary64格式,在binade [1.0,2.0中],最后一个位置的1个单位是2 ^ -52):

    >>> import random
    >>> samples = [random.uniform(1.0, 2.0) for _ in range(10**6)]
    >>> bad = [x for x in samples if 1.0 / (1.0 / x) != x]
    >>> len(bad)
    171279
    >>> min(bad)
    1.4150519879892107
    >>> import math
    >>> math.sqrt(2)
    1.4142135623730951
    

    以下是IEEE 754二进制64格式的示例,表明有必要限制避免下溢:

    >>> samples = [random.uniform(1.0, 2.0) for _ in range(10**6)]
    >>> max(abs(x - 1.0 / (1.0 / x)) for x in samples)
    2.220446049250313e-16
    >>> 2**-52
    2.220446049250313e-16
    

    此处>>> x = 1.3e308 >>> x_roundtrip = 1.0 / (1.0 / x) >>> x.hex() '0x1.72409614c1e6ap+1023' >>> x_roundtrip.hex() '0x1.72409614c1e6cp+1023' 结果与原始结果的不同之处在于最后一个位置的两个单位,因为x_roundtrip小于最小的正常可表示浮点数,因此未表示为与{{{{1}相同的精度1}}。

    最后注意事项:由于IEEE 754-2008也涵盖了十进制浮点类型,我应该提到上述证明几乎逐字逐句地表示十进制情况,确定对于有效数小于1 / x的浮点数,发生往返,而对于一般的十进制浮点数(再次避免溢出和下溢),我们在最后一个地方永远不会被多个单位关闭。然而,需要一些数论理论才能证明关键不等式x总是严格的:最终必须证明数量sqrt(10)永远不是一个平方数(这是是的,但它可能超出了本网站的范围,在此处包含证明。)

    |x - 1/y| < 1/2 10^(1-p)