PHP浮点数比较运算结果不符合预期问题咨询
浮点数比较异常问题解答
根因
这个问题是二进制浮点数通用的精度丢失问题导致的。
十进制下的有限小数(如57.6、177.6)转换为二进制存储时,会成为无限循环小数,受限于浮点数的存储位宽,系统会截断超出精度范围的部分,导致实际存储的值和理论值存在肉眼不可察的微小误差。
你代码中177.6减去120得到的计算结果,实际存储的数值比直接赋值的57.6略小,只是echo、var_dump默认输出时只展示到小数点后1位,将这个误差隐藏了,所以打印结果看起来完全一致,实际底层存储的二进制值并不相等,才会出现比较结果不符合预期的情况。
解决方案
有两种常用的修复方案:
- 方案一:使用高精度数学运算函数处理十进制浮点数
PHP提供了bc系列高精度运算函数,专门用于十进制浮点数的精确计算和比较,入参需传入字符串格式的数值,避免入参本身就存在精度损失:
// 高精度减法,第三个参数指定保留4位小数 $value2 = bcsub('177.6000', '120.0000', 4); // 高精度比较,相等返回0,前者大于后者返回1,前者小于后者返回-1 var_dump(bccomp((string)$value1, $value2, 4) == 0); // 输出bool(true) var_dump(bccomp((string)$value1, $value2, 4) > 0); // 输出bool(false)
- 方案二:放大倍数转为整数后再比较
如果不需要复杂运算,可以将两个数值按照需要的精度放大对应倍数,四舍五入转为整数后再做比较:
// 按保留4位小数的精度,放大10000倍 $precision = 10000; $value1_int = intval(round($value1 * $precision)); $value2_int = intval(round($value2 * $precision)); var_dump($value1_int == $value2_int); // 输出bool(true) var_dump($value1_int > $value2_int); // 输出bool(false)
内容的提问来源于stack exchange,提问作者Karan Adhikari
相关产品推荐
相关产品推荐

