- ベストアンサー
C++の打切り誤差について
- C++の打切り誤差について、なぜ実行結果のsumが1ではなく1.000054や9.99999999999906e-001、9.9999999999990619e-001になってしまうのでしょうか?
- プログラムを実行すると、float型やdouble型の変数の計算結果が正確な値ではなくなってしまいます。
- これは、浮動小数点数の精度に関する誤差が原因であり、特にループ内での計算が積み重なる場合に顕著に現れます。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
「打ち切り誤差」と言ってるので、2進⇔10進の変換を有限桁でやろうとすると、誤差が出るのは御存じなのですよね。 floatやdoubleは、内部では 「a * 2^b : ^はべき乗、 a, bは有限範囲の整数」という形で表現されています。 ※ 正確にはちょっと違いますが、説明のため、等価なものに変換しています。 1/512= 1 * 2^(-9) です。これは、a=1,b=-9と内部表現との間に誤差は出ません。 誤差が無いので、512回足しても 512 * 2^-9 となり、1 * 2^0 ぴったりになります。 対して, 1/10000 を a * 2^b と表現しようとすると、 a,bともに無限の桁が必要で、有限桁では表現できません。そのため、表現できる範囲で打ち切ります。残りが誤差となります。 この誤差のある状態で加えていくので、どんどん誤差が蓄積されていきます。 それが、その実行結果です。 floatとdoubleで差があるのは、a,bの範囲の違いで、floatの方が取れる範囲が小さいため、その分誤差も大きくなります。 これは大抵のプログラム言語や計算ソフトに共通する問題です。 式を工夫して計算順番を変える(1を10000回足して10000で割ったものでは誤差は出ません)、特定の計算に特化した方法を使う(有理数の範囲で使うなら、内部で整数/整数で表現される「有理数クラス」を用意する)等、誤差対策が必要です。
その他の回答 (3)
- asuncion
- ベストアンサー率33% (2127/6289)
まあ、コンピューターがやることですから、 そのくらいの誤差はあるってことです。
- Tacosan
- ベストアンサー率23% (3656/15482)
どうでもいいけど「打ち切り誤差」じゃなくて「丸め誤差」だよね.
- u-bot
- ベストアンサー率58% (1736/2988)
コンピュータが扱う二進数では整数を全て2のn乗の和で表現できます。 しかし小数の場合は2の-n乗の和で表現できない数値があるため記憶する数値に誤差が生じます。 つまり1/512はちょうど2の-9乗のため誤差なく記憶できます。 しかし1/10000=0.0001は2の-n乗の和で表現できないため誤差が生じます。 試しに2のn乗となる数値で割るようにすればオーバーフローを起こさない限り計算結果は1になるはずです。