PHP中的意外行为-相同的代码在C#和Python中给出了正确的结果


Unexpected behavior in PHP - Same code gives correct results in C# and Python

为什么PHP为以下代码返回INF(无穷大):

<?php
$n = 1234;
$m = 0;
while ($n > 0)
{
    $m = ($m * 10) + ($n % 10);
    $n = $n / 10;
}
var_dump($m);
?>

预期结果为4321,但PHP返回INF、浮点类型:

float INF

我用Python和C#编写了相同的代码,并得到了预期的输出-4321

Python

n = 1234
m = 0
while (n > 0):
    m = (m * 10) + (n % 10)
    n = n / 10
print m

C#

static void Main(string[] args)
{
    int n = 1234;
    int m = 0;
    while (n > 0)
    {
        m = (m * 10) + (n % 10);
        n = n / 10;
    }
    Console.WriteLine(m);
    Console.ReadLine();
}

在php中,$n / 10将返回一个浮点数,而不是整数。

所以$n > 0将永远是true

更改while($n > 0)

while($n > 1)while((int)$n > 0),则会得到正确的结果。

PHP是无类型的,并且可以"动态"转换。

这意味着,$n永远不会是"0"或更低,因为在需要时,$n将是一个"float"。

尝试检查<1,你应该没事的。

为了澄清这一点,$n的行为如下:

$n=1234$n=123.4$n=12.34$n=1.234$n=0.1234$n=0.01234等

意思是:$n将始终接近0,但永远不会达到它。这使得$m是无限的,因为循环本身是无限的。

发生的事情是:

$n = $n / 10;

正在执行浮点除法而不是整数除法,因此$n从未达到值0,它只是接近值0,即0.0…1234。

将上述代码更改为:

$n = (int)($n / 10);

将解决问题。

正确的算法使用floor()

<?php
$n = 1234;
$m = 0;
while ($n > 0)
{
    $m = $m * 10 + ($n % 10);
    $n = floor($n / 10);
}
var_dump($m);

这更有可能是因为典型的浮点运算。

如果使用BCMath任意精度数学,则不会产生相同的效果。

$n = 1234;
$m = 0;
while ($n > 0)
{
    $m = bcmul($m, 10) + bcmod($n, 10);
    $n = bcdiv($n, 10);
}
var_dump($m);

http://codepad.viper-7.com/FYNCyN

另请参阅:

http://php.net/manual/en/language.types.float.php

$n = intval($n / 10);

这似乎解决了问题。