话不多说,直接上代码:
$a = 2/9; //output:0.22222222222222 $b = 0.22222222222222.PHP_EOL; var_dump($a == $b); //output:false echo gettype($a).PHP_EOL; //output:double echo gettype($b).PHP_EOL; //output:string exit;
0.22222222222222 == 0.22222222222222 的结果居然是false?这样的结果似乎超出了大部分人的预料,为什么两个一模一样的值 居然不相等??????
翻阅了众多相关资料,其中在 stackoverflow 看到一位网友留下这样一句回答:The test violates a cardinal rule of floating point programming: never do equality comparisons.(该测试违反了浮点编程的一个基本规则:永远不要进行相等比较。)
后来翻阅了PHP官方手册,其中关于浮点数有这么一段警告:
警告(浮点数的精度)
浮点数的精度有限。尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由于取整而导致的最大相对误差为 1.11e-16。非基本数学运算可能会给出更大误差,并且要考虑到进行复合运算时的误差传递。
此外,以十进制能够精确表示的有理数如 0.1 或 0.7,无论有多少尾数都不能被内部所使用的二进制精确表示,因此不能在不丢失一点点精度的情况下转换为二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999999991118...。
所以 永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数。
参见» 浮点数指南网页的简单解释。
这段解释来自PHP官方的具体链接地址:https://www.php.net/manual/zh/language.types.float.php
咋们继续往下说:
经过一番解释,确认了就是因为底层精度问题会导致出现误差,实际上 上面 $a = 2/9; 这段代码的实际结果并不是我们输出看到的 0.22222222222222 我们可以用 sprintf()函数 让2/9真正的结果原形毕露。
咋们以精度20位的形式打印出来 sprintf("%.20f\n", 2/9); ,结果如下:
echo sprintf("%.20f\n", 2/9); //output:0.22222222222222220989
看到了吧,0.22222222222222 怎么可能 等于 0.22222222222222220989 呢?
关于这里出现的这个问题如何解决?
我们可以使用四舍五入保留2位小数的方式进行解决,代码如下:
$a = 2/9; //output:0.22222222222222 $b = 0.22222222222222.PHP_EOL; var_dump(round($a, 2) == round($b, 2)); //output:true var_dump(number_format($a, 2) == number_format($b, 2)); //output:true exit;
这样比较就是大家期望的结果了。
浮点数很棘手,无论进行相等比较 还是大小比较,我们都需要限制小数点的数量。
PHP准确的比较两个浮点数是否相等的方法有:
一、方法一、相减后取绝对值小于一定位数的精度值则相等(PHP官方给出的解决示例办法也是这种方式)
$j = 0.000001; $a1 = 1.000000001; $a2 = 1.000000000; if(abs($a1 - $a2 ) < $j) { echo '精度为6位时相等'.PHP_EOL; } else { echo '精度为6位时不相等'.PHP_EOL; } if(abs($a1 - $a2 ) < 0.0000000001) { echo '精度为10位时相等'.PHP_EOL; } else { echo '精度为10位时不相等'.PHP_EOL; } exit;
方法二、可以用bccomp(参数1, 参数2, 小数位)来比较 该函数也可以用来比较浮点数大小(需要开启bcmath扩展库支持)
bccomp()函数 返回0 则相等,否则不相等
方法三、四舍五入小数点后 指定位数比较 使用php内置的round()函数
可参考:
https://stackoverflow.com/questions/9867108/issue-in-double-value-comparison-with-php
https://blog.csdn.net/guo_qiangqiang/article/details/119910949
声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。
精彩评论