浮点数为何不能进行相等性比较
最近看扎瓦的时候看到了对浮点数的介绍,并且指明浮点数不能进行相等性运算,这个在接触c的时候就知道了,
但是一直不知道为什么。具体的原因不知道也不影响使用,但是不符合我想走的学院派风格,所以大概的看了看。
现在的浮点数在内存中的表示方法有IEEE规定。也不知道为什么是电子电气规定计算机的事。。。
不管是float还是double都是以这种形式存储的。
sign表示符号位,0正 1负应该不陌生,至于后面的exponent,fraction当时老师也没有说,现在我就掰一掰吧。
以一般的64位机为例
float占4个字节,32位。同理,double8个字节64位。
sign exponent fraction
float 1 8 23 32
double 1 11 53 64
这样在内存中存储的形式就很明了了,接下在接解释为什么这样存。
百度百科上是这么解释的:
*二进制浮点数是以符号数值表示法格式储存,将最高效位元指定为符号位元(sign bit);“指数部份”,
即剩下的f位元,为有效位数(significand)减掉有效位数本身的最高效位元。*
翻译过来的意思就是:蓝色框框sign放符号,绿色框框exponent放处理过的指数部分,粉色框框fraction放处理过的转化成二进制的数字。
举个例子
123.123(10)
二进制为: 1111011.00011111011111001110110110010001(2)
你是不是曾天真的以为上面的形式是表示它在计算机里的存储形式是
0 10010011(.)00011111011111001110110?
完全不是,我曾就天真的以为,真正的是这样。
0 10000110(.)11101100011111011111001
它经过我上面说过的“处理”,即
significand:
1111011.00011111011111001110110110010001
转化为科学技术法为
1.11101100011111011111001110110110010001*2^7。
并省略最高为的有效数也就是小数点前的那个“1”,此时因为significand只能存储23位,
则将超出部分去掉,那么,significand就变为:
11101100011111011111001
exponent
这一部分为指数域,其值为偏置量Bias也就是(2^8)-1:127,加上上面科学计数法的指数值
127+7=134(10)=10000110(2)。
那么123.123在内存中的存储形式为:
符号域 指数域 小数域
0 10000110 . 11101100011111011111001
接下来就可以解释一些关于浮点数的精度问题了。
这是我写的一个简单的扎瓦,c可能隐藏这样的问题,但是扎瓦输出就会有问题。反正输出肯定不是0.6
后面跟了一个莫名奇妙的1。
0.4(10) = 0.0110011001100110011001100110011....
0.2(10) = 0.00110011001100110011001100110011....
相加后为
0.10011001100110011001100110011001
在内存中的存储形式:
0 1111110 0011001100110011001100110011001
可以想到,因为计算机对于小数部分的限制,它在处理的时候直接把多出来的截掉了。
我用的是double,它会取前53位。那么0.2和0.4就是损失了精度。结果当然不是0.6。
但是,另宝宝诧异的是,为什么反而多了。。。
要注意,小数部分里,除了0.5(10) = 0.1(2)来表示之外,其他的都是近似值。
目前是比较能说服我的,虽然没有完全弄懂,就当是给以后一个机会吧。