microtimeの差分

まず結論から。

// microtime()の結果aとbの差を計算する
// a-bに相当する秒数を単一のfloat値で返す
function diffmicrotime($a, $b)
{
	list($am, $at) = explode(' ', $a);
	list($bm, $bt) = explode(' ', $b);
	return ((float)$am-(float)$bm) + ((float)$at-(float)$bt);
}

んで、こんなふうに使えます。

// 開始時刻
$start = microtime();

// 2秒ほど実行遅延
sleep(2);

// 終了時刻
$end = microtime();

// 差を出力
echo diffmicrotime($end, $start);

何回か実行すると以下のようになります(実行する)。

2.001753
2.001913
2.001937
2.001808
2.00218

でもまあ、実質3行ながら、なんでこんな面倒くさい関数を作ったのかといいますと…

// 開始時刻
$start = microtime();

// 2秒ほど実行遅延
sleep(2);

// 終了時刻
$end = microtime();

// 差を出力
echo $end-$start;

このシンプルなコードを何回か実行すると以下のようになります(実行する)。

0.002357
0.002567
0.001662
0.002394
0.003047

…(゚д゚)<経過時間0.002秒…

こうなったのは、microtimeの戻り値が秒数の小数部分と整数部分に分かれているために小数部分だけで引き算されたのが原因です。
ではmicrotimeの引数をtrueにして小数で結果を貰ったらどうなるのでしょうか。

// 開始時刻
$start = microtime(true);

// 2秒ほど実行遅延
sleep(2);

// 終了時刻
$end = microtime(true);

// 差を出力
echo $end-$start;

これの実行結果は以下のようになります(実行する)。

2.00226593018
2.00177907944
2.00169491768
2.00232601166
2.00197792053

これもまあ、結果が出ているのでありっちゃありなんですが、実は精度がよくありません。
見た目には桁数が増えていますが、小数第5位あたりで桁落ちが発生しているはずなのでマイクロ秒までは信用できません。
というのも、Unixタイムスタンプをマイクロ秒まで表現するには整数部10桁+小数部6桁の16桁必要ですがPHPのfloat値には約14桁の制度しかないのです(microtime(true)の実行例)。

ということで、最初に示した方法です。
microtimeを引数なしで呼び出すと、整数部分と小数部分が別々に得られて、必要な16桁の精度が保たれます(microtime()の実行例。表示上は小数部8桁だが意味があるのは6桁まで)。
で、別々に計算すると、小数点以下6桁までの精度がそのまま残るというわけです。
それに、この方法だとPHP4でも使えますしね!

// microtime()の結果aとbの差を計算する
// 戻り値は単一のfloat値
function diffmicrotime($a, $b)
{
	list($am, $at) = explode(' ', $a);
	list($bm, $bt) = explode(' ', $b);
	return ((float)$am-(float)$bm) + ((float)$at-(float)$bt);
}

そういうことで、最初に書いたこのコードができるわけです。