Python二级——浮点型数值计算
引言
在python二级考试中,有这样的题目:
print(0.1 + 0.2 == 0.3)
答案是False
对于初学计算机语言的人来说可能很奇怪,难道0.1+0.2不是等于0.3?当然也不是,但这就涉及到计算机语言的浮点型底层存储。
个位小数的加减法失真
先编写代码看看个位小数的加减法
for i in range(1,10):
for m in range(1,i+1):
a='0.{}'.format(i)
b='0.{}'.format(m)
c=eval(a)+eval(b)
print('{}+{}={}'.format(a,b,c),end=' ')
print('')
for i in range(2,10):
for m in range(1,i):
a='0.{}'.format(i)
b='0.{}'.format(m)
c=eval(a)-eval(b)
print('{}-{}={}'.format(a,b,c),end=' ')
print('')
输出结果为
可以看到仅仅是个位小数的加减法,都有如此多的失真情况。
如果只是应对python的二级考试,只需要再编写代码,将其中的失真的找出来就好了
for i in range(1,10):
for m in range(1,i+1):
a='0.{}'.format(i)
b='0.{}'.format(m)
c=eval(a)+eval(b)
if c != round(c,1):
print('{}+{}={}'.format(a,b,c))
for i in range(2,10):
for m in range(1,i):
a='0.{}'.format(i)
b='0.{}'.format(m)
c=eval(a)-eval(b)
if c != round(c,1):
print('{}-{}={}'.format(a,b,c))
运行结果:
0.2+0.1=0.30000000000000004
0.4+0.2=0.6000000000000001
0.6+0.3=0.8999999999999999
0.7+0.1=0.7999999999999999
0.7+0.2=0.8999999999999999
0.7+0.6=1.2999999999999998
0.8+0.4=1.2000000000000002
0.9+0.8=1.7000000000000002
0.3-0.1=0.19999999999999998
0.3-0.2=0.09999999999999998
0.4-0.1=0.30000000000000004
0.4-0.3=0.10000000000000003
0.5-0.4=0.09999999999999998
0.6-0.2=0.39999999999999997
0.6-0.4=0.19999999999999996
0.6-0.5=0.09999999999999998
0.7-0.2=0.49999999999999994
0.7-0.3=0.39999999999999997
0.7-0.4=0.29999999999999993
0.7-0.5=0.19999999999999996
0.7-0.6=0.09999999999999998
0.8-0.1=0.7000000000000001
0.8-0.2=0.6000000000000001
0.8-0.5=0.30000000000000004
0.8-0.6=0.20000000000000007
0.8-0.7=0.10000000000000009
0.9-0.3=0.6000000000000001
0.9-0.6=0.30000000000000004
0.9-0.7=0.20000000000000007
0.9-0.8=0.09999999999999998
貌似有点多,这选择题的一分,咋不要也罢,不过还是要记住几个常见的加法失真的情况。
失真原因:float数值二进制运算
计算机是二进制的数据,int类型进制之间的转化起来十分简单与准确,但是float类型数据转化为二进制就比较麻烦。
- 浮点数储存
浮点数在计算机中存储也是以二进制的形式,遵循IEEE二进制算数标准;格式为:
float : 符号位(首位)、指数位(8位)、尾数(23位)
double:符号位(首位)、指数位(11位)、尾数(52位)
- 十进制浮点数转换为二进制
★方法:
⑴整数部分:除以2,取出余数,商继续除以2,直到得到0为止,将取出的余数逆序
⑵小数部分:乘以2,然后取出整数部分,将剩下的小数部分继续乘以2,然后再取整数部分,一直取到小数部分为零为止。
如果永远不为零,则按要求保留足够位数的小数,最后一位做0舍1入。将取出的整数顺序排列。
★示例:22.8125
⑴整数部分:除以2,商继续除以2,得到0为止,将余数逆序排列。
22 / 2 商11 余 0
11 / 2 商5 余 1
5 / 2 商2 余 1
2 / 2 商1 余 0
1 /2 商0 余 1
得到22的二进制是 : 10110
⑵小数部分:乘以2,取整,小数部分继续乘以2,取整,得到小数部分0为止,将整数顺序排列。
0.8125x2=1.625 取整1 小数部分是0.625
0.625x2=1.25 取整1 小数部分是0.25
0.25x2=0.5 取整0 小数部分是0.5
0.5x2=1.0 取整1 小数部分是0
得到0.8125的二进制是 : 0.1101
⑶结果:十进制:22.8125 等于二进制: 10110.1101
由此可知,当浮点数化成的分数的分母部分是2的倍数时,才有可能完全精度转化二进制数,所以在计算的时候会出现失真情况。