P粉0418569552023-08-22 13:16:54
私は浮動小数点ハードウェアを設計および構築しているので、ハードウェア設計者の観点からいくつかの視点を追加したいと考えました。エラーの原因を知ることは、ソフトウェアで何が起こっているのかを理解するのに役立つ可能性があり、最終的には、浮動小数点エラーが発生し、時間の経過とともに蓄積される理由の説明に役立つことを願っています。
###1。概要###2.標準
標準に従っていますが、一部のプロセッサは非正規化された標準または異なる標準を使用します。たとえば、IEEE-754 には、精度を犠牲にして非常に小さな浮動小数点数を表現できる非正規化モードがあります。ただし、以下では代表的な動作モードであるIEEE-754の正規化モードについて説明します。 IEEE-754 標準では、ハードウェア設計者は、最後のビットの単位の半分未満である限り、任意のエラー/イプシロン値を選択でき、結果は最後のビットの単位の半分未満であることのみが必要です。 1回の操作で。これは、操作を繰り返すとエラーが蓄積される理由を説明します。 IEEE-754 倍精度の場合、仮数とも呼ばれる浮動小数点数の数値部分 (正規化部分) を表すために 53 ビットが使用されるため、これはビット 54 です (例: 5.3e5 の 5.3)。次のいくつかのセクションでは、さまざまな浮動小数点演算におけるハードウェア エラーの原因を詳しく見ていきます。
3. 除算と丸め誤差の原因
および Z = X * (1/Y)
で、乗算の逆関数を使用して除算を計算します。除算は繰り返し計算されます。つまり、必要な精度 (IEEE-754 の場合は最後の桁の誤差の半分未満) に達するまで、商の一部の桁数がサイクルごとに計算されます。 Y の逆数テーブル (1/Y) は、低速除算では商選択テーブル (QST) と呼ばれます。商選択テーブルの桁数は、通常、底の幅、または各反復で計算される商の数に加算した値になります。いくつかのガードビットがあります。 IEEE-754 標準の倍精度 (64 ビット) の場合、除算器の基本サイズにいくつかのガード ビット k を加えたものになります (k>=2
)。したがって、たとえば、一度に 2 ビット (基数 4) で商を計算する一般的な商選択テーブルは、2 2 = 4
ビット (およびいくつかのオプションのビット) になります。
商選択テーブルの逆数は、除算方法によって異なります: 低速除算 (SRT 除算など) または高速除算 (ゴールドシュミット除算など)。各エントリは、除算アルゴリズムに従って変更されます。誤差を最小限に抑えます。いずれにせよ、すべての逆数は実際の逆数の 近似であり、特定の誤差が導入されます。低速除算と高速除算のどちらの方法でも、商を繰り返し計算します。つまり、各ステップで特定の桁数の商を計算し、その結果を被除数から減算し、除数は誤差が最後の半分未満になるまでこれらのステップを繰り返します。桁。遅い除算方法は、各ステップで固定数の商の桁を計算するため、一般的に安価ですが、高速の除算方法は、各ステップで可変数の商の桁を計算するため、一般に高価です。除算方法で最も重要な点は、そのほとんどが の逆数を近似することによる乗算の繰り返しに依存しているため、エラーが発生しやすいことです。
最も近い値に丸める (デフォルト) 、切り捨て、および切り上げがあります。すべての方法で、1 回の操作で発生するエラーは最後のビットの半分未満です。時間の経過と操作の繰り返しにより、切り捨ても累積してエラーが発生します。この切り捨てエラーは、何らかの形式の乗算を繰り返す指数演算の場合に特に問題になります。
Nearest Rounding to Even Numbers などの方法を使用します。これは、時間の経過とともに誤差が互いに打ち消し合う可能性が高くなるためです。 arithmetic を IEEE 754 丸めモード のバリアントと組み合わせて、丸め誤差を予測し、修正します。最も近い偶数桁 (最後のビット) への丸めは、他の丸めモードと比較して相対誤差が低いため、IEEE-754 のデフォルトの丸めモードです。
デフォルトの丸めモード (最も近い偶数桁に丸める) では、最後の桁の 2 分の 1 単位未満の誤差での演算が保証されることに注意してください。切り捨て、切り上げ、切り捨てのみを使用すると、最後の桁の半分単位より大きく、最後の桁の 1 単位未満の誤差が生じる可能性があるため、間隔で計算している場合を除きます。
すべての演算で丸め誤差が発生するもう 1 つの原因は、IEEE-754 で許可されているさまざまな切り捨てモードです。切り捨て、ゼロ方向に四捨五入、
浮動小数点計算を実行するハードウェアは、1 回の演算でユニットの最後のビットの誤差が半分未満の結果を生成するだけでよいため、これを守らないと、演算を繰り返すにつれて誤差が増加します。このため、有限誤差が必要な計算では、数学者は IEEE-754 の
P粉0418819242023-08-22 11:54:59
バイナリ浮動小数点数操作は次のようになります。ほとんどのプログラミング言語では、IEEE 754 標準に基づいています。問題の核心は、この形式では数値が整数と 2 の累乗の積、つまり分母が 2 の累乗ではない有理数 (0.1
のように、##1 を掛けたもの) として表されることです。 /10) を正確に表現できません。
binary64 形式の
0.1 の場合、表現は
とまったく同じように書くことができます。
(10 進数)、または
(
C99 16 進浮動小数点表記 )。
0.1 (
1/10) は、
と正確に書くことができます。
(10 進数)、または
(C99 の 16 進浮動小数点表記に似ており、
... は無限の 9 のシーケンスを表します)。
0.2 および
0.3 も、実際の値の近似値になります。まさに
0.2 最も近い
double は有理数
0.2 より大きいですが、最も近い
double は有理数
より小さいです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 進数の 1/10000 (0.0001)** のようにきれいに見えます** - 2 進数の使用に慣れていた場合私たちの日常生活のシステムでは、その数字を見ても、常に半分に折ることで得られることが直感的に理解できるでしょう。
もちろん、これは浮動小数点数がメモリに格納される方法とまったく同じではありません (浮動小数点数は科学表記法を使用します)。ただし、これは、私たちが通常関心を持っている「現実世界」の数値は 10 のべき乗である傾向があるため、2 進浮動小数点の精度エラーが発生する傾向があるという問題を示していますが、それは私たちが日常的に 10 進数体系を使用しているからにすぎません。これが、「7 個中 5 個」ではなく 71% と言う理由です (5/7 を正確に表すことができる 10 進数はないため、71% は近似値です)。
いいえ、2 進浮動小数点数は壊れているのではなく、他の N 進数体系と同様に不完全なだけです :)
実際には、この精度の問題は、浮動小数点数を表示する前に、丸め関数を使用して、浮動小数点数を目的の小数点以下の桁数に丸める必要があることを意味します。
また、等価性テストを、一定の許容差を許容する比較に置き換える必要があります。これは、次のことを意味します。 if (x == y) { ... }
代わりに、 ここで、 は使用しないでください。
if (abs(x - y) < myToleranceValue) { ... }
を使用してください。 abs
は絶対値関数です。 myToleranceValue
は、特定のアプリケーションに基づいて選択する必要があります。これは、どの程度の「余裕」を許容するか、および比較する最大値 (精度の損失による) に大きく関係します。問題)。選択した言語の「イプシロン」スタイル定数に注意してください。これらの定数は許容値として使用できますが、その有効性は扱う数値のサイズによって異なります (大きな数値の計算ではイプシロンのしきい値を超える可能性があるため)。