如何在这个 32 位 FP 乘法实现中 detect/fix 舍入错误?
How to detect/fix rounding errors in this 32-bit FP multiplication implementation?
我正在尝试理解和实现 32 位浮点乘法。我正在使用 IEEE 754 单精度 FP 格式,其中:
所以我正在关注 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
我看到两个(三个?)问题。
如果有效数的乘积大于或等于2,则指数是错误的。这解释了指数中的差一错误。
您需要应用舍入到偶数逻辑,而不是截断尾数的乘积。这解释了尾数中的差一错误。
您没有正确处理次正规数、无穷大或 NaN(但您可能知道)。
我正在尝试理解和实现 32 位浮点乘法。我正在使用 IEEE 754 单精度 FP 格式,其中:
所以我正在关注 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
我看到两个(三个?)问题。
如果有效数的乘积大于或等于2,则指数是错误的。这解释了指数中的差一错误。
您需要应用舍入到偶数逻辑,而不是截断尾数的乘积。这解释了尾数中的差一错误。
您没有正确处理次正规数、无穷大或 NaN(但您可能知道)。