PHP浮点数精度问题
2020-09-08 本文已影响0人
皮儿吃屁
PHP常见的浮点数“bug”
<?php
$f = 0.58;
var_dump(intval($f * 100)); //为啥输出57
浮点数的表示形式
浮点数的表示(IEEE 754):
- 浮点数, 以64位的长度(双精度)为例, 会采用1位符号位(E), 11指数位(Q), 52位尾数(M)表示(一共64位).
- 符号位:最高位表示数据的正负,0表示正数,1表示负数。
- 指数位:表示数据以2为底的幂,指数采用偏移码表示
- 尾数:表示数据小数点后的有效数字.
小数的二进制表示方式
下面我们具体计算一下0.58的小数表示过程
0.58 * 2 = 1.16 —————— 1
0.16 * 2 = 0.32 —————— 0
0.32 * 2 = 0.64 —————— 0
0.64 * 2 = 1.28 —————— 1
0.28 * 2 = 0.56 —————— 0
0.56 * 2 = 1.12 —————— 1
0.12 * 2 = 0.24 —————— 0
……
0.58 对于二进制表示来说, 是无限长的值
0.58的二进制表示基本上(52位)是: 1001010001111010111000010100011110101110000101000111
如果0.58只是通过这52位计算的话是:
0.58 -> 0.57999999999999996
所以0.58 * 100 = 57.9999999……
精准的浮点数
$x = 8 - 7.74;
$y = 0.26;
var_dump($x == $y); // false
$x = 8 - 7.75;
$y = 0.25;
var_dump($x == $y); // true
0.25的二进制表示0.01,0.26的二进制表示0.0100001……,所以0.25是精准的,而0.26不是。