实例 1
$a = 1.1; |
实例 2
$a = "123456789.1100110011"; |
实例 3
// # 1 |
实例 4
$a = 0.1; |
实例 5
$n = 19.99; |
分析
看文档:
浮点型(也叫浮点数 float,双精度数 double 或实数 real)
浮点数的字长和平台相关,尽管通常最大值是 1.8e308 并具有 14 位十进制数字的精度(64 位 IEEE 格式)。
所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数。
实例 1:说明在 PHP 中 float
与 dobule
是一回事。在 C 级别,所有内容都存储为 double。
实例 2、3:float 的比较结果是 _视情况而定_,永远不要相信浮点数结果精确到了最后一位。
实例 4:出现这个问题是因为浮点数计算涉及精度,当浮点数转为二进制时有可能会造成精度丢失。
- Arbitrary-precision arithmetic library for PHP https://github.com/brick/math
浮点数转二进制方法
整数部分采用除以 2 取余方法,小数部分采用乘以 2 取整方法。
例如:把数字 8.5 转为二进制:
整数部分是 8:
- 8/2=4 8%2=0
- 4/2=2 4%2=0
- 2/2=1 2%2=0
- 1 比 2 小,因此不需要计算下去,整数 8 的二进制为 1000
小数部分是 0.5:
- 0.5x2 = 1.0
- 因取整后小数部分为 0,因此不需要再计算下去,小数 0.5 的二进制为 0.1
8.5
的二进制为 1000.1
。
计算数字 0.9 的二进制:
- 0.9x2 = 1.8
- 0.8x2 = 1.6
- 0.6x2 = 1.2
- 0.2x2 = 0.4
- 0.4x2 = 0.8
- 0.8x2 = 1.6
- … 之后不断循环下去,当截取精度为 N 时,N 后的数会被舍去,导致精度丢失。
实例 4 中 0.9
在转为二进制时精度丢失,导致比较时出现错误。
你看似有穷的小数,在计算机的二进制表示里却是无穷的。
计算数字 0.25 的二进制:
- 0.25x2 = 0.5
- 0.5x2 = 1.0
0.25
的二进制为 0.01
。
float 比较方法
使用 round 方法处理后再比较
var_dump(120085 == round(1200.85 * 100)); |
使用高精度运算方法
见文档 BC 数学 函数 | php.net。
var_dump((1 - 0.9) == 0.1); // bool(false) |
References
– EOF –