在非归一化的数到IEEE754中最小的正常数的一半左右

时间:2019-05-05 07:01:46

标签: floating-point rounding ieee-754

这是一个非常简单的问题,但需要专家回答。

我们知道,浮点数为次标准,我们摆脱了pyinstaller code.py --onefile 2^emin之间的差距。

通过半圆整(RTE)模式,我们应将无限精度结果四舍五入为0还是(0.1111...1|r)*2^emin?该点左侧的数字是隐式位。

第一种情况: 在论文每位计算机科学家应该了解的浮点算术数值计算 中,在图2中,我看到(1.1111...1|r')*2^(emin-1)左侧的空间与其右侧的空间相同。因此,直接地,左数的数值为2^emin(在flp32中为2^emin - 2^(1-p))。如果我们进行RTE舍入,似乎我们应该使用24位有效位之后的位作为舍入位(即p=24,请参见

(0.111_1111_1111_1111_1111_1111|r)*2^emin

我在轴上使用问号(--|---+---+....+-?-|---+---+....+---|-------+........ --0---------------2^emin---------2^emin+1 )代表半点

对于第二种情况:在IEEE标准中,对于次标准检测,在四舍五入之前说“无界”指数blabla。因此,如果我们可以具有无穷大的指数,则可以将精确结果移到?。在这种情况下,我们在(1.1111...1|r')*2^(emin-1)上留了一半大小的左空格。这类似于2^emin上所有其他相邻的空格,但是一旦在轴上接近于0,则空格的数量是无限的。见

2^e

在这种情况下,似乎我们应该将精确结果舍入为

--|...++++|-+-+-+...|---+---+....+-?-|-------+........
--0-....----------2^emin-1----------2^emin
------| here is keep shrinking

通过将情况1的结果左移1位,表示在这种情况下保护位很有用。

在这两种情况下,我们的舍入位不同,因此可能得到不同的结果。 我们应该遵循哪种情况? 我看不到任何有关此主题的文档/论文。

3 个答案:

答案 0 :(得分:6)

未按舍入位或保护位数指定IEEE 754舍入。它是根据real number来指定的,如果我们可以使用精确的实数算法而不是有限精度的浮点进行数学运算,则会产生计算。

当计算的精确值恰好位于两个可表示数字之间的一半时,将舍入到该选项的二分之一至四舍五入,其当前浮点格式的表示将具有一个甚至最低位的尾数位。如果两个选项都写为一个奇数乘以2的幂(并且将0视为具有比其他数字高的2的幂),则也可以认为这是四舍五入到具有更高2的幂的选项。 / p>

保护数字可能会包含在实现中,只要实现产生指定的舍入行为即可。 IEEE 754并没有强制要求任何特定的舍入实现,而只是要求各种舍入模式的行为。

答案 1 :(得分:0)

OP需要实用的方法来测试结果。 Java具有几个有用的属性。其在strictfp模式下的舍入与IEEE754标准匹配,因此可以用作参考实现。该程序说明了如何在32位最小正正数和最大亚正数之间的一半处舍入数字。

public strictfp class Test {
  public static void main(String[] args) {
    printIt(Float.MIN_NORMAL);
    printIt(Math.nextDown(Float.MIN_NORMAL));
    double d = ((double)Float.MIN_NORMAL + (double)Math.nextDown(Float.MIN_NORMAL))/2;
    printIt((float)d);
  }
  static void printIt(float f){
    int bits = Float.floatToIntBits(f);
    String s = Integer.toBinaryString(bits);
    while(s.length() < 32){
      s = "0" + s;
    }
    System.out.println(s);
  }
}

输出:

00000000100000000000000000000000
00000000011111111111111111111111
00000000100000000000000000000000

OP在评论中要求对以下情况进行分析:

n1=Math.nextDown(Float.MIN_NORMAL) + Float.MIN_NORMAL*(2^-24) + Float.MIN_NORMAL*(2^-25) 

n2=Math.nextDown(Float.MIN_NORMAL) + Float.MIN_NORMAL*(2^-24)

我假设中间计算应该以实数而不是float算术完成。

根据我的计算,实数值为:

n1=0.111_1111_1111_1111_1111_1111_1011_1111_1111_1111_1111_1110_1 * MIN_NORMAL
n2=0.111_1111_1111_1111_1111_1111_0111_1111_1111_1111_1111_1111 * MIN_NORMAL

MIN_NORMAL和最大次法线之间的中点是:

0.111_1111_1111_1111_1111_1111_1 * MIN_NORMAL

n1大于中点,因此必须四舍五入到MIN_NORMALn2小于中点,因此必须四舍五入到最大的次法线。这些是我从Java获得的结果。

答案 2 :(得分:0)

我发现了这一点(因为我不是python专家,所以我不确定这是否足够黄金):

import numpy as np
import struct
def float_to_hex(f):
    return hex(struct.unpack('<I', struct.pack('<f', f))[0])
if __name__=='__main__':
    min_normal = np.float64(1*(2**-126))
    max_denorm = np.float64(1*(2**-126)-1*(2**-126)*(2**-23))
    # Emin(-126) * (0.111_1111_1111_1111_1111_1111)_11
    n1 = np.float32(max_denorm+min_normal*np.float64(2**-24)+min_normal*np.float64(2**-25))
    # Emin(-126) * (0.111_1111_1111_1111_1111_1111)_10
    n2 = np.float32(max_denorm+min_normal*np.float64(2**-24))
    # Emin(-126) * (0.111_1111_1111_1111_1111_1111)_01
    n3 = np.float32(max_denorm+min_normal*np.float64(2**-25))

    print(float_to_hex(n1))
    print(float_to_hex(n2))
    print(float_to_hex(n3))

python2 on x86_64 linux的输出是: 0x800000 0x800000 0x7fffff

看起来python2默认情况下遵循round_half_to_even,并在24位有效位之后的一位取整为舍入位。

这是我到目前为止发现的,也许Python或算术专家可以提供一些反馈。

Ps。这个反馈太长了,无法发表评论,所以我把它放在这里@PatriciaShanahan。

感谢帕特里夏