在PHP中使用microtime和浮点加法的数字不精确

时间:2009-06-23 07:49:08

标签: php time floating-point

我很难说服自己在这里做了什么是一个好主意。我发现令人反感的具体部分是:

return ((float)($now+$sec).'.'.$mic);

为了保持浮点精度,我不得不退回BC或GMP库(两者都不可用)。在这种情况下,我使用字符串连接来干扰数字。

<?php

// return the current time, with microseconds
function tick() {
    list($sec, $mic, $now) = sscanf(microtime(), "%d.%d %d");
    return ((float)($now+$sec).'.'.$mic);
}

// compare the two given times and return the difference
function elapsed($start, $end) {
    $diff = $end-$start;

    // the difference was negligible
    if($diff < 0.0001)
        return 0.0;

    return $diff;
}

// get our start time
$start = tick();

// sleep for 2 seconds (should be ever slightly more than '2' when measured)
sleep(2);

// get our end time
$end = tick();

$elapsed = elapsed($start, $end);

// should produce output similar to: float(2.00113797188)
var_dump($elapsed);

?>

如果我尝试添加两个数字,例如 123456789 (表示时间戳)和 0.0987654321 (表示微秒),请使用加法运算符( + )我总是以123456789.099结束。即使将整数转换为float,结果也是一样。

是否有针对此问题的解决方案,1)不是黑客,2)不涉及字符串连接?我不应该依赖于这种乱码,以获得具有微秒分辨率的准确时间戳。

编辑:正如S. Gehrig所解释的那样,PHP中的浮点数有时候显得有些棘手。 PHP配置中指示的“精度”与显示有关。实际值并没有像我想象的那样四舍五入。对上述代码的一个更简单的解决方案就是这样:

// return the current time, with microseconds
function tick() {
    return microtime(true);
}

// compare the two given times and return the difference
function elapsed($start, $end) {
    return $end-$start;
}

// get our start time
$start = tick();

// sleep for 2 seconds (should be ever slightly more than '2' when measured)
sleep(2);

// get our end time
$end = tick();

$elapsed = elapsed($start, $end);

// should produce output similar to: float(2.00113797188)
var_dump($elapsed);

如果您要先检查 $ start $ end ,然后再从另一个中减去一个,则可能会显示它们已四舍五入到百分位。不是这种情况。当显示受限时,似乎保持算术的任意精度。

3 个答案:

答案 0 :(得分:2)

为什么不使用microtime(true)只返回微秒时间戳为float?参数[bool] $get_as_float已在PHP 5.0.0中添加。

关于精确度“损失”的评论:

$start = microtime(true);
$end = microtime(true);
echo $end - $start;
// prints 7.1526861190796

microtime(true)不限于2位小数。海报遇到的是配置设置precision的效果,它控制输出浮点变量时要打印的小数位数。 这与内部精度microtime(true)使用无关。您始终可以使用number_format()(s)printf()将输出格式化为您喜欢的精度。

答案 1 :(得分:1)

首先,spligak,我看到你的代码包含错误。

list($sec, $mic, $now) = sscanf(microtime(), "%d.%d %d");
return ((float)($now+$sec).'.'.$mic);

如果$ mic少于六位数,则会得到垃圾结果。做桌面检查

the case where microtime() returns "0.000009 1234567890"

其次,您可以大大减少浮点错误,如下所示: (警告:未经测试的代码!)

//比较两个给定时间并返回差异

// get our start time
$start = microtime();

// sleep for 2 seconds (should be ever slightly more than '2' when measured)
sleep(2);

// get our end time
$end = microtime();

// work around limited precision math
// subtract whole numbers from whole numbers and fractions from fractions

list($start_usec, $start_sec) = explode(" ", $start);
list($end_usec, $end_sec) = explode(" ", $end);
$elapsed = ((float)$end_usec)-((float)$start_usec);
$elapsed += ((float)$end_sec)-((float)$start_sec);

// please check the output
var_dump($elapsed);

答案 2 :(得分:0)

浮点类型本质上是不精确的。要么与它一起生活,要么不使用它们。