-
Notifications
You must be signed in to change notification settings - Fork 0
/
浮点数运算误差原因.txt
33 lines (20 loc) · 1.41 KB
/
浮点数运算误差原因.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1.示例:
float a = 0.65f;
float b = 0.6f;
float c = a - b;
c的结果是0.049999523而不是0.05
为什么呢?
其根本原因是计算机所使用二进制01代码无法准确表示某些带小数位的十进制数据
我们将0.65及0.6转换为二进制代码:
(0.65)10 = (0.101001100110011001100110011001100110011......)2
(0.6) 10 = (0.10011001100110011001100110011001100110011......)2
后面的省略号表示已经算不完了,后面在无限重复 0011 这段二进制数值。
我们用的float类型,下面我们来看看float类型是否能存储上面转换出的二进制代码。
目前计算机上存储浮点数值是按照IEEE(电气和电子工程师协会)754浮点存储格式标准来存储的。
IEEE单精度浮点格式共32位,包含三个构成字段:23位小数f,8位偏置指数e,1位符号s。将这些字段连续存放在一个32位字里,并对其进行编码。其中0:22位包含23位的小数f; 23:30位包含8位指数e;第31位包含符号s。
也就是说上面将0.65及0.5转换出的二进制代码,我们只能存储23位,即使数据类型为double,也只能存储52位,这样大家便能看出问题出现的原因了。
截取的二进制代码已无法正确表示0.65及0.5,根据这个二进制代码肯定无法正确得到结果0.05。
2.如何解决这个问题?知道其根本原因后,我们知道是无法从根本上解决这个问题的,但我们可以有一些曲线救国的方法,下面列举几个:
2.1 因为二进制数值可以准确表示整数(可以使用整数转换为二进制方法验证下),所以可以将小数乘以10或100等变成整数,然后做运算,最后再通过除以10或100等获得结果
2.2 通过截取结果的有效小数位数等,来取得最好的近似结果,然后在做处理。
2.3 对于可以用有限长度的二进制数值表示的十进制数值,可以使用存储位数大于其长度的数据类型。