话说有一天,我在写一个电商网站的订单结算逻辑,需要把商品价格转换成整数,因为我们的系统只支持整数金额。于是我就很自然地想到了 php 的 intval 函数。但后来我发现,事情没那么简单。
先说下 intval 的基本用法。这函数就是把变量转换成整数,支持第二个参数指定进制,默认是10进制。比如 intval('42') 返回42,intval('0x2A') 返回42,intval('101010', 2) 返回42。
但当我用 intval(4.6) 想四舍五入时,发现返回的是4,而不是我预期的5。这才知道 intval 是直接截断小数部分,不会四舍五入。于是我就改成了 round(4.6),这下返回了5。
但还没完,当我用 round(4.5) 时,发现返回的竟然是4,而不是我预期的5。这让我一脸懵逼。查了下文档,才知道 round 函数默认使用的是"银行家舍入法",也就是当值为5时,会选择最接近的偶数。于是我又改成了 round(4.5, 0, PHP_ROUND_HALF_UP),这才得到我预期的5。
正当我以为问题都解决了时,又遇到一个新问题。当我把浮点数转换成整数时,有时会得到意想不到的结果。比如:
echo intval(19.99 100);
你猜会输出什么?1999?不对,是1998。这是因为浮点数在计算机中是以二进制存储的,存在着精度问题。19.99 100 实际上存储的是 1998.9999999999998。
要解决这个问题,我需要在转换之前先四舍五入:
这下就得到了预期的1999。
但这还没完,还有一个隐藏的坑。当处理大整数时,intval 会截断超出范围的值。比如在32位系统上,intval('999999999999') 会返回2147483647。要避免这个问题,我需要在转换之前先检查是否超出范围:
if (is_numeric($value) && $value <= PHP_INT_MAX && $value >= PHP_INT_MIN) {
$intValue = intval($value);
} else {
// 处理超出范围的情况
}
说到这,你可能会问,那为什么不直接用 round 就好了,还要用 intval?这是因为 round 返回的还是浮点数,不能保证是整数。比如 round(4.6) 返回的是 float(5),而不是 int(5)。所以如果严格需要整数的话,还是得用 intval。
最后总结一下,把 float 转换成 int 时正确的姿势是:
$intValue = intval(round($floatValue));
或者如果是要四舍五入到指定小数位,再转换成整数:
$intValue = intval(round($floatValue, $decimalPlaces));
但要记住处理浮点数精度和整数范围的问题。
以上就是我在使用 php 的 intval 和 round 函数时踩过的坑和总结的经验。希望对你有所帮助,少踩点坑。当然,还有更复杂的情况我没遇到,如果你知道的话,欢迎补充。毕竟,程序员不就是每天在debug和踩坑中度过的吗?生活不止眼前的bug,还有远方的bug在等着我们。但只要我们有一颗热爱技术的心,就没有解决不了的问题。