P粉8185616822023-10-12 11:11:47
私は浮動小数点ハードウェアを設計および構築しているので、ハードウェア設計者の視点を追加する必要があると考えています。エラーの原因がわかれば、ソフトウェアで何が起こっているのかを理解するのに役立つ可能性があり、最終的には、浮動小数点エラーが発生し、時間の経過とともに蓄積される理由の説明に役立つことを願っています。
###1。概要###ほとんどのプロセッサは IEEE-754 標準に従っていますが、一部のプロセッサは非正規化または異なる標準を使用しています。 。たとえば、IEEE-754 には、精度を犠牲にして非常に小さな浮動小数点数を表現できる非正規化モードがあります。ただし、以下では、典型的な動作モードである IEEE-754 の標準化モードについて説明します。
浮動小数点除算エラーの主な原因は、商の計算に使用される除算アルゴリズムです。ほとんどのコンピュータ システムは、主に Z=X/Y
、Z = X * (1/Y)
などの逆乗算を使用して割り算を計算します。除算は繰り返し計算されます。つまり、必要な精度に達するまで商のビット数がサイクルごとに計算されます。IEEE-754 の場合、これは最後のビット誤差が 1 単位未満である任意の値です。 Y の逆数テーブル (1/Y) は、低速除算では商選択テーブル (QST) と呼ばれます。商選択テーブルのサイズ (ビット単位) は、通常、底の幅、または底の桁数になります。 。商は反復ごとに計算され、ガード ビットも加えられます。 IEEE-754 標準の倍精度 (64 ビット) の場合、これは分周器のベースにいくつかのガード ビット k を加えたサイズになります (2 2= 4 ビット (およびいくつかのオプションのビット) になります。
3.1 除算の丸め誤差: 逆数の近似
商選択テーブルの逆数は、division: SRT 除算のような遅い除算、または Goldschmidt 除算のような高速除算によって異なります。各エントリは除算アルゴリズムに従って変更され、可能な限り最小値を生成しようとします。間違い。いずれにせよ、すべての逆数は実際の逆数の近似値であり、何らかの誤差要素が生じます。低速除算と高速除算はどちらも商を繰り返し計算します。つまり、各ステップで商の桁数を計算し、その結果を被除数から減算します。除算器は、誤差が最後の桁の 2 分の 1 未満になるまでこれらのステップを繰り返します。 。遅い除算メソッドは各ステップで固定桁数の商を計算するため、一般に構築コストが低くなります。一方、高速除算メソッドは各ステップで可変桁数を計算するため、一般に構築コストが高くなります。割り算の最も重要な部分は、ほとんどの割り算が逆数の 近似の繰り返しの乗算に依存しているため、間違いを犯しやすいことです。
###4。他の演算における丸め誤差: 切り捨て四捨五入 (デフォルト)、 切り捨て、切り上げがあります。単一の操作の場合、すべてのメソッドで最後に 1 単位未満のエラー要素が発生します。また、切り捨ては、時間の経過や操作の繰り返しにより最終誤差を累積的に増加させます。この切り捨て誤差は、べき乗に何らかの形式の乗算の繰り返しが含まれる場合に特に問題になります。 ###5。操作を繰り返します
に丸められ、1 回の演算での最後の桁の誤差が半分未満になることに注意してください。切り捨て、切り上げ、および切り捨てを単独で行うと、最後の桁の 2 分の 1 より大きく、最後の桁の 1 単位未満の誤差が生じる可能性があるため、これらのモードは区間演算以外には推奨されません。 ###6。まとめ### a>つまり、浮動小数点演算におけるエラーの根本原因は、除算時のハードウェア切り捨てと逆数切り捨ての組み合わせです。 IEEE-754 標準では、単一演算の最後のビットの誤差が 2 分の 1 未満であることだけが要求されているため、繰り返し演算による浮動小数点誤差は修正されない限り蓄積されます。
P粉6053856212023-10-12 10:31:38
バイナリ浮動小数点計算は次のようになります。ほとんどのプログラミング言語では、IEEE 754 標準に基づいています。問題の核心は、この形式では数値が整数の 2 のべき乗、つまり分母が 2 のべき乗ではない有理数 (1/10# である
0.1 など) として表現されることです。 ##) を正確に表現できません。
binary64 形式
0.1 の場合、その表現は
とまったく同じように書くことができます。
(10 進数)、または
C99 16 進浮動小数点表現 .< /a>
0.1 (
1/10) は、
と正確に書くことができます。
(10 進数)、または
は C99 の 16 進浮動小数点表記に似ており、
... は無限に続く 9 を表します。
0.2 および
0.3 も、実際の値の近似値になります。たまたま、
0.2 に最も近い
double は有理数
0.2 よりも大きいですが、最も近い
double code>0.3
は有理数 0.3 より小さいです。
0.1 と
0.2 の合計は、有理数
0.3 よりも大きくなるため、コード内の定数と矛盾します。
すべてのコンピュータ科学者は浮動小数点演算について知っておくべきです。よりわかりやすい説明については、floating-point-gui.de を参照してください。
同じ問題が普通の 10 進数 (基数 10) にも存在します。そのため、1/3 のような数値は 0.333333333...になります。
あなたは、10 進数では簡単に表現できますが、2 進数では表現できない数値 (3/10) を見つけました。また、これは (ある程度) 両方の方向に当てはまります。1/16 は、10 進数では醜い数字 (0.0625) ですが、2 進数では、10,000 番目の 10 進数 (0.0001)** のように見えます。日常生活の中で 2 を基数とする数値体系を使用する習慣があれば、その数値を見て、何かを半分にし、それを何度も何度も半分にすることでその数値に到達できることを直感的に理解できるようになります。もちろん、これは浮動小数点数がメモリに格納される方法とまったく同じではありません (浮動小数点数は科学的表記法を使用します)。ただし、これは、私たちが通常関心を持っている「現実世界」の数値は通常 10 のべき乗であるため、2 進浮動小数点の精度エラーが発生する傾向があることを示しています。ただし、それは単に私たちが昔の 10 進数体系を使用しているからです。これが、「7 個中 5 個」ではなく 71% と言う理由です (5/7 は 10 進数で正確に表すことができないため、71% は近似値です)。
だからいいえ: 2 進浮動小数点数は壊れているのではなく、他のすべての N ベースの数値体系と同じようにたまたま不完全であるだけです :)
実際には、この精度の問題は、浮動小数点数を表示する前に、丸め関数を使用して浮動小数点数を目的の小数点以下の桁数に丸める必要があることを意味します。
また、同等性テストを、ある程度の許容範囲を許容する比較に置き換える必要があります。これは、次のことを意味します。
Don'tDon'tDoif (x == y) { ... }
代わりに、if (abs(x - y) < myToleranceValue) { ... }< myToleranceValue) { ... }
を実行します。
ここで、abs
は絶対値です。 myToleranceValue
選択は、特定のアプリケーションに基づいて行う必要があります。これは、許容する準備ができている「余裕」と、(精度のため) 比較する最大値が何になるかに大きく関係します。損失の問題)。選択した言語の「イプシロン」スタイル定数に注意してください。これらの は許容値として使用できますが、大きな数値の計算はイプシロンのしきい値を超える可能性があるため、その有効性は扱う数値のサイズ (サイズ) によって異なります。