結論から言います。
PHPで小数点を切り捨てるなら、基本的には floor() を使いますが、負の値を扱う可能性があるなら intval() か bcdiv() を選択するのが実務の正解です。
ネット上の適当な記事では「切り捨て=floor()」とだけ紹介されていますが、正直、その程度の理解でコードを書くのは危ういです。
数値の性質(正か負か)や、求められる精度(金融計算など)によって、選ぶべき関数は明確に異なります。
Webエンジニアとして、後から「計算結果が微妙に合わない」といった初歩的なバグで現場を混乱させないよう、1ミリも妥協のない関数の使い分けを脳に叩き込んでください。
執筆者:kazu |
|
単純な「切り捨て」に潜む負の数値の罠
最も一般的な floor() ですが、これは正確には「引数の数値を超えない最大の整数を返す」という数学的な挙動をします。
つまり、正の数のときは私たちがイメージする「切り捨て」になりますが、負の数のときは「値が小さくなる方向」に動きます。
これを理解せずに使うと、負の値を扱った瞬間にロジックが崩壊します。
実務で混乱を招く floor() と intval() の違い
$positive = 1.9;
$negative = -1.1;
// floorは「床」。常に数値が小さい方へ向かいます
echo floor($positive); // 1
echo floor($negative); // -2 (ここが罠です)
// intvalは「整数化」。単純に小数点以下を無視します
echo intval($positive); // 1
echo intval($negative); // -1
上記の通り、floor(-1.1) は -2 になります。
「単に小数点以下を消し去りたい」という意図であれば、intval() を使うのが最短ルートです。
「とりあえずfloor」という脳死の選択は、負のデータが入ってきた瞬間に技術負債へと変わります。
仕様として「0の方向へ近づけるのか」「無限に小さい方向へ飛ばすのか」を、実装前に0.5秒で判断する癖をつけてください。
任意の桁数で切り捨てる際に「10倍して戻す」のが非効率な理由
「小数点第2位で切り捨てたい」という要望に対し、floor($num * 100) / 100 といったコードをよく見かけますが、私はおすすめしません。
なぜなら、コンピューターの浮動小数点数の精度問題(計算誤差)に足を掬われるリスクがあるからです。
浮動小数点数の演算で発生する「1ミリも効率的じゃない」誤差
$num = 0.58;
// 0.58 * 100 は内部的に 57.99999... になることがあります
echo floor($num * 100) / 100;
// 結果が 0.57 になるという、最悪のバグを引き起こします
こうした「計算によって発生する誤差」を考慮せず、力技で解決しようとするのはプロとして論外です。
たかだか1桁の切り捨てでデバッグに数時間を溶かすのは、非効率の極みと言えます。
精度を求める現場での正解は BCMath 関数です
もしあなたが扱っている数値が、決済金額や統計データなど「1円、1単位のズレも許されない」ものなら、迷わず bcdiv() を使ってください。
BCMathライブラリは数値を文字列として扱うため、前述した浮動小数点数の誤差を完全に回避できます。
bcdiv() を使ったスマートな桁指定切り捨て
$num = "0.58"; // 文字列として扱うのがコツです
// 第2引数は割る数。1で割れば数値は変わらない
// 第3引数(スケール)に、残したい小数点以下の桁数を指定する
echo bcdiv($num, '1', 1); // 0.5
echo bcdiv($num, '1', 2); // 0.58
このコードの前後でやっていることは非常にシンプルですが、信頼性は floor を使った計算よりも圧倒的に高いです。
「効率的なプログラミング」とは、単に文字数を減らすことではなく、こうした「確実に動く標準機能」を適材適所で選択することに他なりません。
まとめ:kazuが提唱する「切り捨て」の規律
PHPでの小数点切り捨てを、単なる「おまじない」にしないでください。
正の数だけなら floor()。
負の数を含めて「小数点以下削除」なら intval()。
任意の桁数指定、あるいは厳密な精度が必要なら bcdiv()。
number_format() は表示用であり、計算ロジックに混ぜるのは論外。
これらを区別できないエンジニアが書いたコードは、後から必ず修正の手間が発生します。
最初から「正解」を選び、無駄なハマり時間を削る。
それがプロのエンジニアとしての流儀です。
以上です。



コメント