【PHP】小数点の切り捨てはfloor一択ではない | 負債を生まない関数の使い分け

【PHP】小数点の切り捨てはfloor一択ではない | 負債を生まない関数の使い分け PHP

結論から言います。

PHPで小数点を切り捨てるなら、基本的には floor() を使いますが、負の値を扱う可能性があるなら intval()bcdiv() を選択するのが実務の正解です。

ネット上の適当な記事では「切り捨て=floor()」とだけ紹介されていますが、正直、その程度の理解でコードを書くのは危ういです。

数値の性質(正か負か)や、求められる精度(金融計算など)によって、選ぶべき関数は明確に異なります。

Webエンジニアとして、後から「計算結果が微妙に合わない」といった初歩的なバグで現場を混乱させないよう、1ミリも妥協のない関数の使い分けを脳に叩き込んでください。

【執筆者の簡易プロフィール】
kazu 執筆者:kazu
  • 38歳男性、既婚
  • Webエンジニア
  • 新卒でSESに入社し、Web系企業に常駐、その後Web系スタートアップに転職
  • 主な使用言語はRuby、PHP、JavaScript、HTML/CSS
  • モットーは「人に厳しく、自分にはもっと厳しく」

単純な「切り捨て」に潜む負の数値の罠

最も一般的な 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() は表示用であり、計算ロジックに混ぜるのは論外。

これらを区別できないエンジニアが書いたコードは、後から必ず修正の手間が発生します。

最初から「正解」を選び、無駄なハマり時間を削る。
それがプロのエンジニアとしての流儀です。

以上です。

コメント

タイトルとURLをコピーしました