如何在这个32位FP乘法实现中检测/修复舍入误差?

时间:2017-02-23 17:36:52

标签: python algorithm floating-point multiplication ieee-754

我试图理解并实现32位浮点乘法。我使用IEEE 754单精度FP格式,其中:

enter image description here

所以我跟随this walkthrough of the algorithm。使用bitstream.pack我可以将浮点数转换为IEEE 754格式的一串位,所以我这样做并将其与我尝试手动实现算法时得到的结果进行比较。

然而,看起来我在尾数和指数上的舍入问题大约有50%的时间。任何人都可以看到我在这里错误实施的内容吗?如果没有,有没有办法检测并纠正这些舍入错误?

import bitstring, random 

successes = 0
failures = 0

def ieee754(float):
    b = bitstring.pack('>f', float)
    sbit, wbits, pbits = b[:1], b[1:12], b[12:]
    return sbit.bin + wbits.bin + pbits.bin

def extract_parts(bits):
    m = bits[9:]     # 23 bits 0-22 are mantissa
    e = bits[1:1+8]  # 8 bits 23-31 are exponent
    s = bits[:1]     # bit 32 is sign
    return s, e, m 

tests = [(-18.0, 9.5), (134.0625, -2.25), (-14.5, -0.375), (7.5, 15.5), (1.2, 23.1), (-0.5, -0.2)]

for a, b in tests:
    #a = random.uniform(-10, 10)
    #b = random.uniform(-10, 10)

    a_s, a_e, a_m = extract_parts(ieee754(a))
    b_s, b_e, b_m = extract_parts(ieee754(b))

    # sign is exclusive-or of signs
    s = '1' if int(a_s) != int(b_s) else '0'

    # exponent is sum of exponents minus 127 'bias'
    e = int(a_e, 2) + int(b_e, 2) - 127

    # mantissa is product of mantissas with a 1 added as their MSB
    # then we ignore the MSB of the result
    m = '{0:023b}'.format(int('1' + a_m, 2) * int('1' + b_m, 2))[1:24]

    # convert to binary strings for comparison
    e = '{0:08b}'.format(e)

    print("Calculated:\t", (s, e, m));
    print("Expected:\t", extract_parts(ieee754(a*b)))

    if((s, e, m) == extract_parts(ieee754(a*b))):
        print("Success with", a, b); successes += 1
    else:
        print("Failure with", a, b); failures += 1

print("Successes", successes, "Failures", failures)

这些是我的结果:

Calculated:  ('1', '10000110', '01010110000000000000000')
Expected:    ('1', '10000110', '01010110000000000000000')
Success with -18.0 9.5

Calculated:  ('1', '10000111', '00101101101001000000000')
Expected:    ('1', '10000111', '00101101101001000000000')
Success with 134.0625 -2.25

Calculated:  ('0', '10000000', '01011100000000000000000')
Expected:    ('0', '10000001', '01011100000000000000000')
Failure with -14.5 -0.375

Calculated:  ('0', '10000100', '11010001000000000000000')
Expected:    ('0', '10000101', '11010001000000000000000')
Failure with 7.5 15.5

Calculated:  ('0', '10000011', '10111011100001010010000')
Expected:    ('0', '10000011', '10111011100001010001111')
Failure with 1.2 23.1

Calculated:  ('0', '01111011', '10011001100110011001101')
Expected:    ('0', '01111011', '10011001100110011001101')
Success with -0.5 -0.2

1 个答案:

答案 0 :(得分:2)

我看到两个(三个?)问题。

  1. 如果有效数的乘积大于或等于2,那么指数是错误的。这解释了指数中的逐个错误。

  2. 您需要应用舍入到偶数逻辑,而不是截断有效数字的乘积。这解释了有效数字中的逐个错误。

  3. 你没有正确处理次正规,无穷大或NaN(但你可能知道)。