例によって小ネタです。
小数点以下n桁で四捨五入した小数をvar_exportでダンプしようとしてみた
$a = 3.1419526535;
var_dump(round($a,2));
echo var_export(round($a,2),true) . PHP_EOL;
float(3.14)
3.1400000000000001 <------- Σ(゚Д゚)
何がいけなかったの?
困った時はPHPマニュアルを参照参照...特に何も書いてないな。
じゃあStackOverflowさんに聞いてみるか…
php, var_export fails with float
wtf?(What the fuck, 何だコレ?)だって
確かに何だコレ。です。
ここに書かれてある「serialize_precision」がクサイ。
そこでもう一度マニュアルのコメント欄まで見てみると、PHP5.4.22からiniファイルの「serialize_precision」を見るようになった。デフォルトは17だよと書いてた。
なんで17?と思いつつ、じゃあ精度下げてみるかってことに。
とりあえずの解決方法
ini_set('serialize_precision', 16);
$a = 3.1419526535;
var_dump(round($a,2));
echo var_export(round($a,2),true) . PHP_EOL;
float(3.14)
3.14 <------- (ー。ー)フゥ
serialize_precisionを16以下にするといいみたいです。
serialize_precisionについて
こちらに「すごくシンプルな」説明がありました。
浮動小数点数をシリアライズするときに格納する桁数を指定します。
シリアライズ?ってことは、ひょっとするとserializeにも影響するの?json_encodeも怖いから確認してみましょう。
ini_set('serialize_precision', 17);
echo serialize(round($a,2)) . PHP_EOL;
echo json_encode(round($a,2)) . PHP_EOL;
ini_set('serialize_precision', 16);
echo serialize(round($a,2)) . PHP_EOL;
echo json_encode(round($a,2)) . PHP_EOL;
d:3.1400000000000001;
3.14
d:3.14;
3.14
serializeには影響しましたが、json_encodeには影響しませんでした。どういう理屈なんだろう?
serialize_precisionのデフォルト値の意味
よくわからないのですが、マニュアルの浮動小数点の説明に
PHP は通常 IEEE 754 倍精度フォーマットを使います。 この形式は、1.11e-16 のオーダーでの丸め処理で誤差が発生します。
とあるのですが、これと関係ありそうな気もします。
(詳しい方のコメントお待ちしています!)
結論: floatな値をvar_exportしたとき人の目に優しく出力するには「serialize_precision」を設定するべし
でもserialize_precisionはグローバルなので、他の箇所に影響しないよう注意してくださいね!
ちなみに
この記事はPHP Disではありません!(笑)