【PHP】number_formatの四捨五入を防ぐ考え方と実装

【PHP】number_formatの四捨五入を防ぐ考え方と実装のイメージ php

PHPのnumber_format関数は数字を千の位毎にグループ化してフォーマットする関数です。
数値にカンマをつけたい、そんな場合に利用する関数です。

number_format関数の挙動のおさらい

number_format(float $num, /* フォーマットする数値。*/
    int $decimals = 0,/* 小数点以下の桁数 */
    ?string $decimal_separator = ".", /* 小数点を表す区切り文字。*/
    ?string $thousands_separator = ","/* 千の位毎の区切り文字。*/
): string

小数を含むフォーマットの場合には注意が必要です。number_format関数内で丸め(四捨五入)が働きます。

echo 12339960/1000;

結果は12339.96です。
12,339.9」と表示させたいのですが、number_formatではうまくいきません。

echo number_format(12339960/1000,1);

結果は12,340.0です。
小数第二位で繰り上げが発生してしまいます。

number_formatの挙動は以下の通りです。

  • $decimals = 0、小数第一位で繰り上げ(四捨五入)
    echo number_format(12339960/1000);

    結果は12,340です。
    これは、下の0を小数の桁として指定した場合と同等です。

    echo number_format(12339960/1000,0);

    結果は12,340です。
    小数第一位で四捨五入されていますね。
    ちなみにnumber_format(1.4)は1、number_format(1.5)は2という結果になります。

  • $decimals = 1、小数第二位で繰り上げ(四捨五入)
    echo number_format(12339960/1000,1);

    結果は12,340.0です。
    1を小数の桁と指定した場合、小数第二位で四捨五入されます。

  • $decimals = 2、小数第三位で繰り上げ(四捨五入)
    echo number_format(12339960/1000,2);

    結果は12,339.96です。
    2を小数の桁と指定した場合、小数第三位で四捨五入されます。

number_formatの四捨五入を防ぐ考え方

四捨五入の対象となる位を切り捨てします。これで四捨五入を防げます。

小数の桁 サンプルソース
小数の桁0 echo number_format(floor(1.5));
floorで1.5→1にしています
小数の桁1 echo number_format(floor(1.55*10)/10,1);
floorで15.5→15、1.5に戻しています
小数の桁2 echo number_format( floor(1.555*100)/100,2);
155.5→155、1.55に戻しています
小数の桁3 echo number_format( floor(1.5555*1000)/1000,3);

つまり、こんな関数を用意すれば解決できます。

function my_format( float $num,int $decimals = 0,?string $decimal_separator = ".",?string $thousands_separator = ","): string{
    $rate = pow( 10, $decimals);
    return number_format( floor($num*$rate)/$rate , $decimals, $decimal_separator,$thousands_separator);
}
echo my_format( 12339960/1000,1 );

結果は12,339.9です。四捨五入されずに、求めている結果になりました☺️

まとめ:正の値はこれでいけます。負の値は危険かも?

正の値はこのロジックで大丈夫だと思います。負の値は、floorの挙動に納得できるなら大丈夫ですが、求めているのと違う場合、正と負で処理を切り分ける等の修正が必要です。

echo floor(4.3);   // 4
echo floor(9.999); // 9
echo floor(-3.14); // -4

コメント

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