A. 用Python计算9.4 - 9得到的结果为0.40000000000000036。
B. 结果用32位浮点数表示为:
0 01111101 1001 1001 1001 1001 1001 101
这是因为尾数只能保存23位,尾数最低位应该“0舍1入”,所以结果如上。
C. 下面分析为何Python计算9.4-9的结果为0.40000000000000036:
本人的计算机中存储的浮点数采用的是双精度浮点数,那么
+9.4转换为二进制即23×1.00101100110(0110循环),用64位浮点数表示
0 10000000010 0010 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
-9用64位浮点数表示
1 10000000010 0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
阶码相同,无需对阶,两个浮点数尾数相减得
0010 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
-
0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
=
0000 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
将尾数首次出现的1视作规约数隐藏的1,并在尾数后补0凑齐52位,变换成
100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 0000 0
阶码应相应退阶-5,变为
(10000000010)B - (5)D = (01111111101)B
所以9.4-9计算结果用64位浮点数表示
0 01111111101 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 0000
用所编写的程序将该64位浮点数转换成实际的十进制数得到的结果为0.40000000000000035527,由于计算机保留的位数有限,最后经过四舍五入后打印出来的数为0.40000000000000036。
这个问题本质上是由于浮点数位数有限,在尾数的最低位有“0舍1入”的操作,造成了与实际值的误差。对于某个十进制数,当其转换成二进制数时尾数不断循环的话,这种误差无法避免。
附录代码:
import numpy as np
# 直接打印输出9.4-9
def test_fun():
a = 9.4-9
print(a)
# 将32位浮点数转换为实际的十进制数
def cal_float32(ee, mm):
"""
:param ee: ee为输入参数,以10进制表达指数位;
:param mm: mm为输入参数,以0/1序列表示23位小数位;
:return: F32为输出参数
"""
mm_list = np.float64(list(mm))
mesa_multi = 2 ** np.float64((np.arange(-1, -24, -1)))
if ee == 0:
E = 2 ** (-126)
F32 = E * np.sum(mm_list * mesa_multi)
else:
E = 2 ** (np.float64(ee) - 127)
F32 = E * (1 + np.sum(mm_list * mesa_multi))
return F32
# 将64位浮点数转换为实际的十进制数
def cal_float64(ee, mm):
"""
:param ee: ee为输入参数,以10进制表达指数位;
:param mm: mm为输入参数,以0/1序列表示52位小数位;
:return: F64为输出参数
"""
mm_list = np.float64(list(mm))
mesa_multi = 2 ** np.float64((np.arange(-1, -53, -1)))
if ee == 0:
E = 2 ** (-1022)
F64 = E * np.sum(mm_list * mesa_multi)
else:
E = 2 ** (np.float64(ee) - 1023)
F64 = E * (1 + np.sum(mm_list * mesa_multi))
return F64
# 十进制整数转二进制
def int_decimal_to_binary(par):
"""
:param par: par为输入的十进制整数
:return: 输出为二进制的list
"""
binary_result = []
while par != 0:
r = divmod(par, 2)
par = r[0]
remainder = r[1]
binary_result.append(remainder)
binary_result.reverse()
return binary_result
# 十进制小数部分转二进制
def man_decimal_to_binary(par):
"""
:param par: par为输入的十进制小数部分
:return: 输出为二进制的list
"""
binary_result = []
par -= int(par)
while par != 0:
par *= 2
if par >= 1:
binary_result.append(1)
par -= int(par)
else:
binary_result.append(0)
return binary_result
# 十进制数部分转二进制
def decimal_to_binary(par):
"""
:param par: par为输入的十进制数(包含整数小数)
:return: 输出为二进制的list
"""
integer = int_decimal_to_binary(int(par))
mantissa = man_decimal_to_binary(par-int(par))
integer_str = [str(i) for i in integer]
mantissa_str = [str(i) for i in mantissa]
binary_result = "".join(integer_str) + "." + "".join(mantissa_str)
return binary_result
# 整数二进制转十进制
def int_binary_to_decimal(par):
"""
:param par: par为输入的二进制整数,类型为字符串
:return: 输出为十进制数
"""
return int(par, 2)
# 二进制小数部分转十进制
def man_binary_to_decimal(par):
"""
:param par: par为输入的二进制小数部分,类型为字符串(不包含0.)
:return: 输出为二进制的list
"""
mesa_multi = 2 ** np.float64((np.arange(-1, -(len(par)+1), -1)))
par_list = np.float64(list(par))
decimal_result = np.sum(par_list * mesa_multi)
return decimal_result
if __name__ == '__main__':
# 直接打印输出9.4-9,打印结果为0.40000000000000036
test_fun()
# 为了得到9.4和9两个数的浮点数,应先将它们转换成二进制数再来计算
result1 = decimal_to_binary(9.4)
result2 = decimal_to_binary(9)
# 得到9.4的64位浮点数为0 10000000010 0010 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101
# 得到-9 的64位浮点数为1 10000000010 0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
# 9.4-9浮点数计算结果为0 01111111101 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 0000
# 具体计算过程见作业报告,利用程序将该浮点数结果转换成实际十进制数并打印
result3 = cal_float64(1021, "1001100110011001100110011001100110011001100110100000")
# 人为保留20位小数,结果为0.40000000000000035527
print('%.20f' % result3)