用PHP进行整数的除法
首先
注意事项:当在PHP中进行整数除法时(无法整除时,将会舍弃小数部分),请注意要获得此类结果。
结论。
如果使用PHP7及更高版本,则可以使用intdiv($x, $y)。
如果是PHP5.6,最好将($x – ($x % y)) / $y等于这个值。
经常被介绍的intval($ x / $ y)有时会产生错误的值。
说明 (jiě shuō)
为什么intval($x / $y)不行呢?
在PHP的运算符说明中,写着以下这样的解释。(代数运算符)
除算运算符 (“/”) 返回的值将是浮点数。但是,如果两个操作数都是整数(或可以转换为整数的字符串),且结果能整除,则返回整数值。有关整数除法,请参阅 intdiv()。
由于PHP的浮点数比整数精度低,比如将9999999999999999(9为16位数)除以10得到余数为999999999999999(9为15位数),但实际结果并非如此。
% php -r 'var_dump(9999999999999999 / 10);'
float(1.0E+15)
% php -r 'var_dump(intval(9999999999999999 / 10));'
int(1000000000000000)
在整数部分的除法阶段,由于浮点数的精度无法处理,结果被舍入了,所以无法正确地将小数点以下的值截断。
整除函数
由于浮点数运算会引起各种麻烦,因此在PHP7中新添加了一个名为intdiv的函数,用于执行整数运算,简单直接。
% php -r 'var_dump(intdiv(9999999999999999, 10));'
int(999999999999999)
这是为此目的而设计的,所以没有问题。
在没有intdiv函数的5.6版本中怎么办?
由于没有intdiv,我们只能想办法解决这个问题。/ 运算符在可以整除的情况下进行整数运算,所以如果事先通过减法去除余数使其能够被整除,计算将会正确。
% php -r 'var_dump(9999999999999990 / 10);'
int(999999999999999)
如果以($x – ($x % y)) / $y的形式来总结,将是一个不错的选择。
更详细一些
“虽然说当可以整除时会返回整数值,但可能会有人指出没有提及中间计算的情况,所以为了确认,请检查源代码。执行除法运算的是Zend/zend_operators.c中的div_function()函数。当两个整数进行运算时,执行的部分是这样的。”
case TYPE_PAIR(IS_LONG, IS_LONG):
if (Z_LVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
return SUCCESS;
} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
/* Prevent overflow error/crash */
ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
return SUCCESS;
}
if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
} else {
ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
}
return SUCCESS;
在此情况下,可以看到当能整除时,使用整数除法,无法整除时则将其转换为浮点数并进行除法运算(这种情况下并不构成问题,但是在C中,整数相除将舍弃小数部分(向0方向取整)作为数学商,这是C的规定)。
整型的最小值(PHP_INT_MIN)除以-1得到一个超出整数范围的结果,因此特殊处理了这种情况,这感觉很明显。