言語(PHP他)PHP
投稿日 : 2020年11月9日

【PHP】sprintfは四捨五入保証がない-五捨六入されていた話-

【PHP】sprintfは四捨五入保証がない-五捨六入されていた話-の画像

こんにちわ、PHPエンジニアのエンジニア婦人(@naho_osada)です。
私はPHPエンジニアとして7年~の経験があります。WordPressは2年半~の経験があります。その他、jQuery、HTML、CSSも使用します。
ここでは主に過去に納品した案件や自サイト運営(エンジニア婦人ノート)で遭遇したことについて書いています。

今回はPHPで数字を扱う処理を作ったときにやらかした話です。どこかで勘違いしてそのまま…

小数点一桁表示でよろしく!

ある案件で、数字を表示することがありました。

そのときに「何桁まで出しますか?」と聞いて「小数点第一位表示で」とのことでした。

その表示ならフォーマット整形、sprintfでいいなと思って実装しました。

sprintf("%0.1f", 小数点以下のある何かの数値);

こうなりますね。

数値は小数点第二位を四捨五入した小数点第一位までの表示して、特別問題がなさそうに見えました。

sprintfは四捨五入しない場合がある

検証を続けていくと、四捨五入されない場合があることがわかりました。四捨五入されることもあるけど、されないこともある。

echo sprintf("%0.1f", 2.24);
echo sprintf("%0.1f", 2.25);
echo sprintf("%0.1f", 2.26);

これを実行してみるとわかりますが…四捨五入じゃなくて、五捨六入されています…!

公式にも「四捨五入する」とは書いてない

PHP公式のsprintfのページをみてみると、なんと四捨五入するとは書いていませんでした。

ずっと四捨五入はsprintfの0.1fでもOKと思い込んでいたのだけれど、一体どこで記憶違いしたんだろう。Perlかな(でもPerlもroundあるよね)
…これまでやってきたどこかで、思い違いをしていたようです。

五捨六入になっていた考えられる原因

恐らく浮動小数点の関係でずれてしまうのだと思われます。内部的には四捨五入しているのかしら。

正解はこちら

echo round(2.24, 1);
echo round(2.25, 1);
echo round(2.26, 1);

roundで丸めます。そのあとさらに整形の必要があるならばsprintfを使用します。

まとめ

厳密なる数値を扱うときに、sprintfは使ってはいけません。ずれます。

round / floor / ceilを目的によって使い分けましょう。

数字で使うときはしかるべき関数(round / floor / ceil)を使ったのちに使用しましょう。