C++

【C++】浮動小数点数の誤差(double→floatで値が変わる)

投稿日:2018年3月15日 更新日:


C++で下記の2つのメソッドに3.6fを引数に渡すと異なる結果になります。

test135を返し、test236を返します。

3.6 / 0.1なので、36が欲しい結果なので35を返すtest1の実装だとNGなわけです。

違いはfloatの変数に入れているだけなのですが、なぜ計算結果が変わるのでしょうか。

今回はteratailで質問してみました!

質問の内容は下記のリンクから確認出来ます。

teratail:【C++】floatをintへ変換する際の挙動の違いについて

質問してすぐに3人の方から回答頂き、無事に理解が出来ました!

結論からお話すると、浮動小数点数の誤差とキャスト時の丸め処理の違いが原因でした。

では詳しく解説していきます。

※浮動小数点の誤差は、開発環境(コンパイラやOSなど)によって異なります。
上記のサンプルの計算結果にならない環境の方が多いみたいです。

スポンサーリンク

原因その1:浮動小数点数の誤差が発生していた

浮動小数点数の誤差が発生している事がわかりました。

計算結果をdoubleで受けてみると、下記の値になっていました。

35.99999849999995

計算に使っている少数が2進数だと表現できない循環小数だったのでこのような誤差が出ているんですね。

ただこれだけだと、test1とtest2の計算結果が異なる理由にはなりませんね。
test1とtest2で同じように浮動小数点数の誤差が発生しているわけですから。

原因その2:floatに代入する事で四捨五入されていた

teratailではこのように回答を頂きました。

test1はdoubleを直接intへ変換してます。test2はdoubleを一旦floatへ変換後intへ変換してます。

これは、実際にキャスト処理イメージしてみるとわかりやすいです。

test1の場合

double35.99999849999995を直接intへ変換します。
doubleからintへの変換では、小数点以下は切り捨てです。

なので、限りなく36に近い35.9999…でも35になってしまうですね。

test2の場合

こちらのケースは、まずdouble35.99999849999995floatへ変換します。

この時に、floatの方がdoubleより有効桁数が小さいので、floatの有効桁数に収まるように四捨五入されます
floatの有効桁数は6桁です。

有効桁数に収まるように四捨五入すると、36.0になるわけですね。

36.0のfloatをintに変換する時はそのまま36のままです。
小数点以下を切り捨てても変わらないので。

ようするに…

test1とtest2の結果の違いは、キャストの方法が違いから丸めの処理も異なっているのが原因だったんですね!

test1は、小数点以下を切り捨て
test2は、有効桁数6桁で四捨五入

なるほど!スッキリしました!

対応策

理屈は理解出来ました!

理解できたところで、test1もtest2も正確な計算結果を返す保証がないことがわかりました。

test1は、既に前述の通り誤った値を返しています。

test2は前述のケースでは正しい値を返していますが、それはたまたま四捨五入の結果正しい値になっただけです。

test1と同様に誤った値を返すケースもあるでしょう。

なので、対応策を調べてみました。
対応策になるのはこのあたりだと思います。

  • BigDecimalを使う
  • 整数で処理する
  • 有効桁を決めて四捨五入する

おわりに

計算系の処理を実装する時は気をつけないといけませんね!

特に小数点を扱うような処理の時は要注意です!

それにしても、teratailにはすごく助けられました。

投稿してから最初の回答をもらうまで5分!
早すぎてびっくりしました!笑

一人で考えていると煮詰まっちゃうときってありますよね。
そういう時は、誰かの意見を聞くとパッと視界がクリアになって理解出来ちゃう時があるんですね。

自宅で一人で仕事していて、相談相手がいない僕のような人でも気軽に質問できるteratailは救世主的存在ですね!

プログラミングで困ったことがあれば、是非使って見る事をオススメします!

teratail

スポンサーリンク


-C++

執筆者:

関連記事

no image

【C++】なにも代入していないクラス変数に値が入っている理由

こんにちは、C++の案件を年に1度だけ対応するプログラマーこへいんです。 今回は変数の初期化について。 Javaプログラマーの僕がなんで?って思った事について調べてみました。 スポンサーリンク 目次変 …

C++のメモリ管理について

こんにちは! こへいんです。 僕は毎年この時期になると、C++のソフトウェアの改修案件が入ってきます。 普段は、JavaやPHPで開発していて、この時期だけC++を触るのですが、久しぶりに触ると初歩的 …

フォスターフリーランス
プロフィール

このサイトを運営しているこへいんです。
アングラーのフリープログラマー。 主にプログラミングと釣の話を発信しています。
プログラミングで自由になり思う存分に釣りをしまくる生活実践中。
詳しいプロフィールはこちら