标题:PHP的除法 出处:Felix021 时间:Fri, 04 Dec 2015 20:49:27 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?2151 内容: 今天要实现一个简单的功能:按需给出长度为n的空格串。 如果是用Python,我就直接用这一句来解决了,既简单又直观: ' ' * n 可惜PHP就是不好使,只好写一个函数。最简单的办法当然是一个循环,但是看起来太蠢了,效率也低(虽然可以用一个数组缓存来解决),看起来也不帅。所以试着写了一个递归的版本(其实也应该要用数组来缓存提高效率,但是以下代码省略了相关逻辑,看起来清晰一点): function spaces($n) { if ($n == 1) return ' '; return spaces($n / 2) . spaces($n - $n / 2); } 看起来酷多了对不对? 不对……因为一调用就递归到死啊魂淡。什么破玩意,连这种代码也不能一次跑对,简直让我对自己的能力产生了怀疑。 好吧,那就调试一下。 function spaces($n) { if ($n == 1) return ' '; printf("%d = %d + %d", $n, $n / 2, $n - $n / 2); fgetc(STDIN); return spaces($n / 2) . spaces($n - $n / 2); } printf竟然输出了"3 = 1 + 1",这尼玛我都要开始怀疑人生了,什么鬼! 经过各种折腾,最后不知为什么放弃治疗,用了大概这样的代码(说真的,我在运行之前都觉得这是徒劳): function spaces($n) { if ($n == 1) return ' '; var_dump($n / 2); var_dump($n - $n / 2); fgetc(STDIN); return spaces($n / 2) . spaces($n - $n / 2); } 输出: 引用 float(1.5) float(1.5) 卧槽…… 卧槽…… 卧槽…… 重说三。 当时已经接近崩溃了,于是到Google去试图寻找一点安慰,“php int division get float”返回给我的第一条,竟然是一个StackoverFlow的问题:How do I get a float value when dividing two integers? (PHP),提问者表示他用 12 / 13 得到的结果是 1 。SF的大神们纷纷出招,甚至还有人回答: 引用 Just use $value = (float)($x/$y); 我看着左边的-1,深藏功与名。 然后继续解决问题。我想知道为什么我这儿两个整数一除就变成了浮点数,然而试了几个不同的环境,都是一样的,看起来倒了这血霉的似乎不是我一个。 查来查去也没查出什么来,于是我鼓起勇气、抛弃羞耻心,找到了一个我觉得我这辈子都不会需要打开的页面: PHP:算术运算符 - http://php.net/manual/zh/language.operators.arithmetic.php 这个页面标题里的第一句话是“还记得学校里学到的基本数学知识吗?就和它们一样。”。 接下来是一个表格,列出了负号、加、减、乘、除、取余的说明。 表格后面还跟了一句话: 除法运算符总是返回浮点数。 除法运算符总是返回浮点数。 除法运算符总是返回浮点数。 尼玛……这说的学校居然TMD是小学啊……我了个大槽……谁家小学还教 “% 取余” 符号的!!谁家小学教的除法返回浮点数还带余数的!! 然而我还是不太相信,我用了八九年的PHP,我竟然不知道它没有整数除法? 翻,翻源码。 在 php5-src/Zend/zend_vm_def.h 可以看到 除法操作符(ZEND_DIV )的Handler,调用的是 fast_div_function ,这个函数里面有一段被注释掉的老的实现,目前实际调用的是 div_function ,实际上都是一样的,截取后者的一部分: ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { zval op1_copy, op2_copy; int converted = 0; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): if (Z_LVAL_P(op2) == 0) { zend_error(E_WARNING, "Division by zero"); ZVAL_BOOL(result, 0); return FAILURE; /* division by zero */ } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) { /* Prevent overflow error/crash */ ZVAL_DOUBLE(result, (double) 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; .... 真的什么都不用说了。 EDIT UPDATE: 那个stackoverflow的问题,其实有人在问题的评论里指出了结果本来就是浮点数,不知道提问者怎么脑抽的。 EDIT UPDATE 2: PHP 7新增了一个 intdiv 函数,还真是非常PHP-Style的函数名和解决方法,看着就令人蛋疼。 Generated by Bo-blog 2.1.0