誤差
こんにちは!タカモリです。 今日は誤差について勉強しましょう!前回、固定小数点数や浮動小数点数について書いていきましたが、32ビットであれ何ビットであれ、パソコンには処理できる数の範囲が決まっているということは大体想像がつくかと思います。 ということは!発生するんですよね。そう。。誤差が!つまり自分が欲しかった結果と違う計算結果がコンピュータから返ってくる。これが誤差です。
一口に誤差と言っても、実は発生する原因によって以下の5つの誤差に分類することができます。
- 桁あふれ誤差(アンダーフロー・オーバーフロー)
- 情報落ち
- 打ち切り誤差
- 桁落ち
- 丸め誤差
本日はこれらの違いについて一緒に見ていきたいと思います。
桁あふれ誤差
オーバーフロー
例えばコンピュータが扱える数の最大値が100で最小値が-100だったとします。この数を上回り101という数字や-101という数を扱わなければならない場合はどうなるでしょう。
そうです!表現できる範囲の限界を超えている為、表示させることができません。これをオーバーフローと言います。なおこの状況での100を超えた場合を「正のオーバーフロー」-100を下回った場合を「負のオーバーフロー」と言います。
アンダーフロー
ではアンダーフローとは一体なんなのでしょうか?これは、扱う数が限りなく0に近い数の場合に発生する誤差のことです。
例えば0.00000000000...001や-0.00000000000...001などの数の場合に発生します。 一見アンダーフローは名前からして、-100.....のようなイメージがありますが、それは負のオーバーフローということになりますので注意が必要です。
情報落ち
では続いて「情報落ち」です。 これは、絶対値の大きな値と小さな値を計算した場合に発生する誤差です。 むむ?となりますが、例えば浮動小数点数で仮数部が4桁の0.1111 × 10の4乗 + 0.1111×10の-4乗という計算します。
答えは、0.111100001111となると思われますが、仮数部が4桁の浮動小数点数なので答えは0.1111×10の4乗となり、せっかく足したはずの0.1111×10の-4乗が反映されません。
打ち切り誤差
続いては「打ち切り誤差」です。 例えば1 ÷ 3 のように答えが0.3333333...のように無限に小数点が続いてしまうような計算(無限小数)の場合、途中でコンピュータが計算を打ち切ってしまいます。 これによって発生する誤差を打ち切り誤差と言います。これはわかりやすいですね!
丸め誤差
続いては「丸め誤差」です。 例えば0.1111111...111...のように桁数が多くなってしまい、有効な桁数未満の数を「切り捨て」「切り上げ」「四捨五入」などして削除することによって発生する誤差です。
桁落ち
続いては「桁落ち」です。これは、「値がほぼ等しくかつ丸め誤差を持つ数値同士の差を求めた結果、有効数字が減少することを桁落ちと呼びます。
先ほど上で丸め誤差について説明したかと思いますが、丸め誤差は有効桁数未満を切り捨てている。ここまでは分かりますよね。 では、例えば0.448×10の7乗 - 0.446×10の7乗の結果が0.002×10の7乗だった場合を考えましょう。この0.002×10の7乗は有効桁数が3桁から1桁に減っていますが浮動小数点数により正規化され0.200×10の5乗となってしまいます。
これの問題点は、もしかしたら0.448*10の7乗は丸め誤差により、元の数字が四捨五入等されているかもしれません。しかし桁落ちによって堂々と結果が0.200×10の5乗と、さも初めからここには0がありましたよ!というような姿で0が入るのです。
桁落ちについては僕自身よくわからなかったので、結構調べたのですが、つまり「答えが正しいかどうかもわからんのに堂々と0を出すな!」こういうことだと思います。
今回はそれぞれの誤差について僕なりの解釈も踏まえながら説明していきました。正直なところ完全に理解したというよりかは、「ふわっと理解した。」こんな感じです。もう少し僕に知識がついたら是非更に分かりやすいような解説ができたらと思いますのでぜひ今後ともよろしくお願いします。
もえもえさん
アドレス計算は二進数だけど、普通に紙や画面に表示するのに使うのはパック10進数だと気がついた笑 パック10進数はカンマ編集できる命令が用意されてるのが理由だと思う。昔から使ってるからそれが普通だと思ってた笑 で、パック10進数なんだけど少数点以下が使えないので事前に100万倍しておいて編集する時に適切なところで少数点のピリオド付きで編集してる笑
タカモリ
アセンブリはバリバリ2進数ですよね! 実際の業務での工夫は勉強になります?♂️ 高級言語がいかに、2進数を考えなくてよいかを実感する毎日です笑
もえもえさん
オーバーフローは自分の環境ではシステムエラーとなるのでオーバーフローしない設計をしてます。 波動小数点の丸めは、丸めが起きても業務に影響が出ないように最初から100万倍した数値を使ったりしてますね。 実数に戻す時に100万で割ってます。
タカモリ
おぉ!めっちゃわかりやすい! 勉強していてもイメージがなかなかつかない部分があるので、具体例をだしてもらえると、めっちゃ助かります? あ、おはようございます☀️
退会ユーザー
floatやdoubleは、浮動小数点数なので、必ず桁落ちします。 なので、お金の計算など桁落ちすると困るものには絶対に使えません。 画像サイズ変換など、多少桁落ちしても問題ないものにはいいですが。 JavaScriptの数値は、基本的にdoubleなので注意しましょう。 JavaScriptならBigNumberなどのライブラリ、 JavaならBigDecimalクラス、PHPならBC Mathなどを使って、 小数の精度や端数処理(切り捨て・切り上げ・四捨五入)を指定して、桁落ちしない計算が必要です。 数年前、為替レート計算をJavaScriptで計算してるプログラムがあって、 バグ修正で、すべての計算をBigNumberに書き換える作業をやったこともありますね。