Dec
4
今天要实现一个简单的功能:按需给出长度为n的空格串。
如果是用Python,我就直接用这一句来解决了,既简单又直观:
可惜PHP就是不好使,只好写一个函数。最简单的办法当然是一个循环,但是看起来太蠢了,效率也低(虽然可以用一个数组缓存来解决),看起来也不帅。所以试着写了一个递归的版本(其实也应该要用数组来缓存提高效率,但是以下代码省略了相关逻辑,看起来清晰一点):
看起来酷多了对不对?
不对……因为一调用就递归到死啊魂淡。什么破玩意,连这种代码也不能一次跑对,简直让我对自己的能力产生了怀疑。
好吧,那就调试一下。
printf竟然输出了"3 = 1 + 1",这尼玛我都要开始怀疑人生了,什么鬼!
经过各种折腾,最后不知为什么放弃治疗,用了大概这样的代码(说真的,我在运行之前都觉得这是徒劳):
输出:
卧槽……
卧槽……
卧槽……
重说三。
当时已经接近崩溃了,于是到Google去试图寻找一点安慰,“php int division get float”返回给我的第一条,竟然是一个StackoverFlow的问题:How do I get a float value when dividing two integers? (PHP),提问者表示他用 12 / 13 得到的结果是 1 。SF的大神们纷纷出招,甚至还有人回答:
我看着左边的-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 ,实际上都是一样的,截取后者的一部分:
真的什么都不用说了。
EDIT UPDATE: 那个stackoverflow的问题,其实有人在问题的评论里指出了结果本来就是浮点数,不知道提问者怎么脑抽的。
EDIT UPDATE 2: PHP 7新增了一个 intdiv 函数,还真是非常PHP-Style的函数名和解决方法,看着就令人蛋疼。
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
如果是用Python,我就直接用这一句来解决了,既简单又直观:
' ' * n
可惜PHP就是不好使,只好写一个函数。最简单的办法当然是一个循环,但是看起来太蠢了,效率也低(虽然可以用一个数组缓存来解决),看起来也不帅。所以试着写了一个递归的版本(其实也应该要用数组来缓存提高效率,但是以下代码省略了相关逻辑,看起来清晰一点):
function spaces($n)
{
if ($n == 1)
return ' ';
return spaces($n / 2) . spaces($n - $n / 2);
}
{
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);
}
{
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);
}
{
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)
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;
....
{
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的函数名和解决方法,看着就令人蛋疼。
欢迎扫码关注:
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
依云
2016-4-28 08:03
大概是因为太多的人需要用浮点除时会忘记显式转浮点型来除。我觉得这样子也没什么问题的呀。当然取决于之前的语言背景,肯定会有人习惯有人觉得别扭的。这没办法……
依云
2016-4-24 20:42
Python 3 现在也默认除法返回浮点数了。不过它还有整数除法的运算符~
felix021 回复于 2016-4-27 01:59
是吗……这个有点坑啊。我查了下,PEP238(@2001)就说了这回事……为毛不是用//来当true division,感觉语言设计者脑抽了。
分页: 1/1 1