📝
PHPで浮動小数点数を文字列に正しくキャストする
ある日のこと
PHPでfloatの値を BCMath 関数 で計算するために、文字列にキャストしようとしました。
$num = 0.00001;
var_dump((string) $num);
出力結果
string(6) "1.0E-5"
おや?様子がおかしいぞ...
ということで何が起こっているのか調べてみました。
よりよい方法やバグ等ございましたら、アドバイスいただけると光栄です。
何が起こっているのか
どうやらサーバー上で数字を表示する場合、小数点表記で表示できる値に制限があり
0.0001
未満になると指数表記に変換されてしまうとのこと。
なので、下記のように実行すると
var_dump(0.0001);
var_dump(0.00009);
var_dump(0.00001);
そもそもfloatの時点で指数表記になっている。
出力結果
float(0.0001)
float(9.0E-5)
float(1.0E-5)
文字列にキャストすると、上記の値がそのまま文字列に変換されるので
小さな値の場合は指数表記で出力されてしまう。
出力結果
string(6) "0.0001"
string(6) "9.0E-5"
string(6) "1.0E-5"
どうすれば正しくキャストできるのか
sprintf関数 を使って以下ように変換すればOK。
var_dump(sprintf('%.5F', 0.00001));
出力結果
tring(7) "0.00001"
フォーマット文字列である %.5F
は、以下のような意味を持つ。
文字列 | 意味 |
---|---|
% | フォーマットの接頭辞 |
.5 | ピリオド(.)の後に小数点の後ろに表示する桁数を入力 |
F | 引数を小数として扱い、ロケールを考慮せずに浮動小数点数値として出力 |
おまけ
sprintf関数 のフォーマットでロケールを考慮するかどうかみたいな話が出てきたので
何が違うんだ?と思って少し調べてみました。
ロケールをフランスに変換して実行すると
setlocale(LC_NUMERIC, 'fr_FR'); // ロケールをフランスに変換
var_dump(sprintf('%.5f', 0.00001)); // ロケールを考慮する
var_dump(sprintf('%.5F', 0.00001)); // ロケールを考慮しない
出力結果
string(7) "0,00001"
string(7) "0.00001"
なんと小数点の表記が違っていました!
どうやらフランスでは、小数点をカンマ(,)で表記するらしいです。
Discussion