0.1+0.2=0.3?
先看一段程序代码,判断下输出会是什么:
|
|
结果会输出什么?会输出 值为0.3 ?
错误!正确输出为 值不为0.3 !为什么?
其根本原因是计算机所使用二进制01代码无法准确表示某些带小数位的十进制数据。
下面,我们来分析下:
我们知道将一个十进制数值转换为二进制数值,需要通过下面的计算方法:
整数部分:连续用该整数除以2,取余数,然后商再除以2,直到商等于0为止。然后把得到的各个余数按相反的顺序排列。简称”除2取余法”。
小数部分:十进制小数转换为二进制小数,采用”乘2取整,顺序排列”法。用2乘以十进制小数,将得到的整数部分取出,再用2乘余下的小数部分,然后再将积 的整数部分取出,如此进行,直到积中的小数部分为0或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,即先取出的整数部分作为二进制小数的 高位,后取出的整数部分作为低位有效位。简称”乘2取整法”。
按照上述方法,我们把0.1和0.2分别转换为其对应的二进制数据表示:
|
|
后面的省略号表示已经算不完了,后面在无限重复0011 这段二进制数值。
目前计算机上存储浮点数值是按照IEEE(电气和电子工程师协会)754浮点存储格式标准来存储的。
以下摘自查阅资料
浮点数, 以64位的长度(双精度)为例, 会采用1位符号位(E), 11指数位(Q), 52位尾数(M)表示(一共64位).
符号位:最高位表示数据的正负,0表示正数,1表示负数。
指数位:表示数据以2为底的幂,指数采用偏移码表示
尾数:表示数据小数点后的有效数字.
假设数据类型为双精度浮点数类型,也只能存储52位,该小数的二进制代码已无法正确表示0.1及0.2,根据这个二进制代码肯定无法正确得到结果0.3。
就像鸟哥一篇博客说的那样:”你看似有穷的小数, 在计算机的二进制表示里却是无穷的”。所以尽量不要去比较浮点数值。
小结
关于浮点数值计算会产生误差的问题,这是使用基于IEEE754数值的浮点计算的通病,PHP并非独此一家,其他使用相同数据格式的语言也存在这个问题!
- 原文作者:maratrix
- 原文链接:https://maratrix.cn/post/2014/07/14/php_float_false_notes/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。