浮動小数点数を使用する場合の致命的なバイナリ算術エラー

コンピューターテクノロジーで実数を表現するためのさまざまな形式の中で、IEEE754標準に記録されている浮動小数点数形式(PTN)には特別な場所が与えられています。 ご存じのように、浮動小数点数の主な利点は、計算値が広範囲の値で計算できることです。計算は、コンピューティングデバイスに簡単に実装できるバイナリ算術ツールによって編成されます。 ただし、後者の状況には落とし穴がたくさんあり、この形式を使用して計算を行うと、まったく予期しない結果が生じる可能性があります。

以下に、誤った結果につながるいくつかの浮動小数点数の算術演算の例を示します。 これらの結果は、計算が実装されるプラットフォームに依存しません。

この記事では、これらのエラーの原因を説明する理論的な計算は行いません。 これは次のトピックのトピックです。 ここでは、2進算術を使用して10進数で算術演算を実行するときに生じる計算の壊滅的な不正確性の問題に専門家の注意を向けようとします。 ここで説明する例は、IEEE754標準で解釈される浮動小数点形式を使用することの妥当性を容赦なく示唆しています。

CNCでの誤った計算の原因は、主に丸め誤差ではなく、その除去が標準で多くの注意を払われているためではなく、10進数と2進数の変換の性質そのものであることに注意してください。

NTCには、floatとdoubleの2つの主な形式を検討します。 フロート形式では、24ビットを含む2進仮数で最大7桁の有効な10進数を表現できることを思い出してください。 double形式は、53桁の2進数を含む仮数部で最大15桁の有効な10進数を表します。

バイナリマシンワードで表現できない10進数は、10進数に変換された後、有効な数字と無効な数字の「テール」の両方を含んでいます。 これらの「テール」は、バイナリ演算を使用した10進数の実際のTECの誤った計算の原因です。 これを例で示します。

金額


したがって、まず、それぞれが7つの有効な有効数字を持つ、float形式で表示される次の2つの実数の合計を検討します。

0.6000006 + 0.03339874 = 0.63339934≈0.6333993

すべての計算はフロート形式で実行されます。 明確にするために、アンパック形式の数字を使用します。 正規化されたバイナリ形式の10進数を想像してください。

0.6000006≈1.001100110011001101001 * 2 ^(-1)
0.03339874≈1.00010001100110100011110* 2 ^(-5)

結果のバイナリコードが再び10進数で表される場合、次の値を取得します。

0.6000006≈0.6000006198883056640625≈0.60000062
0.03339874≈0.033398739993572235107421875≈0.03339874

ここでは、7桁の正しい数字に丸められた各数字は、スペースで「テール」から分離されています。 これらの「テール」は、機械仮数で書かれたバイナリコードから10進コードへの数値の逆変換の結果です。
バイナリ24ビット形式の数値の合計は、次の結果になります。

1.001100110011001101001 * 2 ^(-1)+ 1.00010001100110100011110 * 2 ^(-5)≈1.0100010001001100111011 * 2 ^(-1)≈0.6333994

10進数を「テール」で合計すると、同じ結果が得られます。

0.6000006 2+ 0.0333987 4 = 0.63339936≈0.6333994

ご覧のとおり、7桁の有効数字に丸めた後、ここで得られる結果は、計算機で10進数を合計した結果とは異なります。 IEEE754標準に固有の数値のバイナリ表現の丸め規則は、ここで説明する数値の正確な計算の問題を解決しません。 この場合、エラーの原因は、10進数の最後の正しい数字に続く数字の組み合わせにありますが、先験的には不明です。

追加の例をもう1つ示します。 電卓で次の2つの実数を合計します。各実数には7つの有効な10進数が含まれています。

6543.455 + 12.34548 =6555.80048≈6555.800

10進数の項を2進数の正規化形式にします。

6543.455 = 1.10011000111101110100100 * 2 ^ 12 = 6543.455 078
12.3454810 = 1.10001011000011100010110 * 2 ^ 3≈12.345 48

これらの用語を2進数形式で合計すると、次の2進数が得られます。

1.10011001101111001101 * 2 ^12≈6555.80078125≈6555.801

ここで、変換されていない10進数の計算機で計算された結果とは異なる結果が再び得られました。

乗算


不正確な計算の同じ問題は、フロート形式のバイナリで提示されたいくつかのNTPの積を見つけるときに発生します。 たとえば、次の実数の積を考えます。

0.06543455 * 139 = 9.09540245≈9.095402

この式で、正規化されたバイナリ形式で因子を表します。

0.06543455 = 1.00001100000001010001101 * 2 ^(-4)
139 = 1.0001011 * 2 ^ 10

バイナリ形式で数値を乗算した結果は数値になります。

1.00001100000001010001101 * 2 ^(-4)×1.0001011 * 2 ^ 10 = 1001.00011000011011000101≈9.095403

作業の下位カテゴリでエラーが発生しました。これは、バイナリコードで表される数値を丸めても修正できません。 このようなエラーは一般に致命的と呼ばれます。

分割


乗算と同様に、一部のTNTのフロート形式での除算操作も致命的なエラーにつながります。 次の例を考えてみましょう。

131 /0.066≈1984.848

正規化された形式で、バイナリ形式の被除数と除数を想像してください。

13110 = 1.0000011 * 2 ^ 7
0.066 = 1.00001110010101100000010 * 2 ^(-4)

数値を除算する商は次のようになります。

1.0000011 * 2 ^ 7 / 1.00001110010101100000010 * 2 ^(-4)=
= 1.11110000001101100100111 * 2 ^ 10 = 1984.8485107421875≈1984.849

ここで得られた結果は、計算機または手動で計算された正しい値に対応していないことがわかります。

減算


減算は、バイナリ算術を使用してCTNの10進数値を計算するという考えを完全に否定する操作です。 この操作の結果、場合によっては、ほとんど真実ではない結果を得ることができます。 これを例で示しましょう。

削減を105.3256とします。 それから数105.32を引きます。 手動で計算されたこれらの数値の差は、次と等しくなります。

105.3256-105.32 = 0.0056

正規化されたバイナリ形式で10進数のデクリメントと10進数の減算を想像してください。

105.3256 = 1.10100101010011010110101 * 2 ^6≈105.3255997 041015625
105.32 = 1.10100101010001111010111 * 2 ^6≈105.32

これらの数値の違いをバイナリ形式で見つけます。

1.10100101010011010110101 * 2 ^ 6-1.10100101010001111010111 * 2 ^ 6 = 1.01101111 * 2 ^(-8)

この数値を10進数に変換すると、次のようになります。

1.01101111 * 2 ^(-8)= 0.005599976

予想とは大きく異なる結果が得られました。

ダブルエラー

致命的なエラーが発生する状況では、doubleなどの高精度形式は保存されません。 上で述べたように、これは数字をある数字体系から別の数字体系に変換するというまさにその性質によるものです。 これを例で示します。

推論の正しさをチェックするためのツールとして、Excel75を使用します。これは、IEEE754規格の仕様に厳密に従って計算を実装します。

Excel 2009ツールを使用して次の計算を実行し、数値としてセル形式を選択します(小数点以下18桁)。 金額を確認するには、Excelテーブルのセルに次の数値を書き込みます。

A1 = 0.6236
A2 = 0.00661666666070646

セルA3Excelでは、これらの数値の合計を取得します。

A3 = A1 + A2 = 0.6236 +0.00661666666070646≈0.630216666660707

この金額を手動または計算機で計算すると、数値が得られます:

0.6236 +0.00661666666070646≈0.630216666660706

どちらが低いかは、Excelで受信したものと一致しません。

Excelの減算演算が何につながるかを見てみましょう。 セルに次の数字を入力します。

A1 = 123456.789012345
A2 = 123456

セルA3で、これらの数値の違いを見つけます。 以下と等しくなります。

A3 = A1-A2 = 0.789012345005176

そして、我々は数を取得することを期待していました:

123456.789012345-123456 = 0、789012345


結論として、減算演算を行わなくても、バイナリ算術を使用して10進数の実数を計算する場合、エラーがどれほど速く成長するかの例を示します。
Excelテーブルのセルに次の数値を書き込みます。

A1 = 0.500000000660006
A2 = 0.0000213456548763
A3 = 0.00002334565487363
A4 = 0.000013345654873263

セルA6には、式= A1 / 5 + A2を記述します。 その後、結果が取得されます。

A6 = A1 / 5 + A2 = 0.100021345786878

セルA7では、次の計算を実行します。

A7 = A6 / 3 + A3 = 0.0333637942504995

計算してみましょう

A8 = A7 / 4 + A4 = 0.00835429421749813

計算機で同じ計算をしましょう。 15桁の有効数字の精度で計算を実行します。 算術の規則に従って、最下位桁の右側にある数値は、最も近い整数に丸められます。 その結果、次のようになります。

A1 / 5 = 0.500000000660006 / 5 = 0.1000000001320012≈0.100000000132001
A1 / 5 + A2 = 0.100000000132001 +0.0000213456548763≈0.100021345786877
(A1 / 5 + A2)/ 3 = 0.100021345786877 /3≈0.0333404485956257
(A1 / 5 + A2)/ 3 + A3 = 0.0333404485956257 +0.00002334565487363≈0.0333637942504993
[(A1 / 5 + A2)/ 3 + A3] / 4 = 0.0333637942504993 /4≈0.00834094856262483
[(A1 + 5 + A2)/ 3 + A3] / 4 + A4 = 0.00834094856262483 + 0.000013345654873263 = 0.00835429421749809

計算で得られた結果とExcelで発生した算術演算のルールを比較すると、10進浮動小数点数に2進算術演算を使用すると、完全に予測できない結果になる可能性があります。

Source: https://habr.com/ru/post/J309812/


All Articles