14. 浮動小数点演算:問題と制限—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/2.7/tutorial/floatingpoint
移動先:案内検索

14.14。 浮動小数点演算:問題と制限

浮動小数点数は、コンピューターハードウェアでは基数2(2進数)の分数として表されます。 たとえば、小数部

0.125

値は1/10 + 2/100 + 5/1000で、同じように2進数の分数です。

0.001

値は0/2 + 0/4 +1/8です。 これらの2つの分数の値は同じですが、実際の違いは、最初の分数が基数10の分数表記で記述され、2番目の分数が基数2で記述されていることだけです。

残念ながら、ほとんどの小数は2進分数として正確に表すことはできません。 結果として、一般に、入力する10進数の浮動小数点数は、実際にマシンに格納されている2進数の浮動小数点数でのみ概算されます。

この問題は、10進数で最初は理解しやすいです。 分数1/3を考えてみましょう。 これを基数10の分数として概算できます。

0.3

または、より良い、

0.33

または、より良い、

0.333

等々。 書き留めても構わないと思っている桁数に関係なく、結果は正確に1/3になることはありませんが、1/3の近似値はますます良くなります。

同様に、使用する基数2の桁数に関係なく、10進値0.1を基数2の小数として正確に表すことはできません。 基数2では、1/10は無限に繰り返される分数です

0.0001100110011001100110011001100110011001100110011...

任意の有限ビット数で停止すると、近似値が得られます。

Pythonを実行している一般的なマシンでは、Python浮動小数点に53ビットの精度が利用できるため、10進数0.1を入力したときに内部に格納される値は2進数です。

0.00011001100110011001100110011001100110011001100110011010

これは1/10に近いですが、正確には等しくありません。

インタープリタープロンプトでfloatが表示される方法のため、格納された値が元の小数部の近似値であることを忘れがちです。 Pythonは、マシンによって保存された2進近似の真の10進値に対する10進近似のみを出力します。 Pythonが0.1で保存されたバイナリ近似の真の小数値を出力する場合、次のように表示する必要があります。

>>> 0.1
0.1000000000000000055511151231257827021181583404541015625

これは、ほとんどの人が役立つと思うよりも多くの桁数であるため、Pythonは、代わりに丸められた値を表示することにより、桁数を管理しやすくします。

>>> 0.1
0.1

これは、実際には幻想であるということを理解することが重要です。マシンの値は正確に1/10ではなく、実際のマシン値の表示を単純に丸めているだけです。 この事実は、これらの値を使用して算術演算を実行しようとするとすぐに明らかになります。

>>> 0.1 + 0.2
0.30000000000000004

これはまさにバイナリ浮動小数点の性質であることに注意してください。これはPythonのバグではなく、コードのバグでもありません。 ハードウェアの浮動小数点演算をサポートするすべての言語で同じ種類のものが表示されます(ただし、一部の言語では、デフォルトで、またはすべての出力モードで違いが表示されない場合があります)。

これから他の驚きが続きます。 たとえば、値2.675を小数点以下2桁に丸めようとすると、次のようになります。

>>> round(2.675, 2)
2.67

組み込みの round()関数のドキュメントには、ゼロからのタイを丸めて、最も近い値に丸めると記載されています。 小数部2.675は2.67と2.68のちょうど中間であるため、ここでの結果は2.68(の2進近似)になると予想される場合があります。 10進文字列2.675が2進浮動小数点数に変換されると、正確な値が2進近似に再び置き換えられるため、そうではありません。

2.67499999999999982236431605997495353221893310546875

この近似値は2.68よりも2.67にわずかに近いため、切り捨てられます。

10進数の中間大文字をどちらに丸めるかが気になる状況にある場合は、 10進数モジュールの使用を検討する必要があります。 ちなみに、 10進数モジュールは、特定のPython浮動小数点数に格納されている正確な値を「確認」するための優れた方法も提供します。

>>> from decimal import Decimal
>>> Decimal(2.675)
Decimal('2.67499999999999982236431605997495353221893310546875')

もう1つの結果は、0.1は正確に1/10ではないため、0.1の10個の値を合計しても正確に1.0にならない可能性があることです。

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.9999999999999999

バイナリ浮動小数点演算には、このような多くの驚きがあります。 「0.1」の問題については、以下の「表現エラー」セクションで詳しく説明します。 その他の一般的な驚きのより完全な説明については、浮動小数点の危険性を参照してください。

それが終わり近くに言うように、「簡単な答えはありません」。 それでも、浮動小数点に過度に注意しないでください。 Pythonのfloat演算のエラーは、浮動小数点ハードウェアから継承され、ほとんどのマシンでは、演算ごとに2 ** 53の1つの部分しかありません。 これはほとんどのタスクには十分すぎるほどですが、これは10進演算ではなく、すべてのfloat演算で新しい丸め誤差が発生する可能性があることに注意する必要があります。

病理学的なケースは存在しますが、浮動小数点演算のほとんどのカジュアルな使用では、最終結果の表示を期待する10進数に単純に丸めると、最終的に期待する結果が表示されます。 フロートの表示方法を細かく制御するには、 Format String Syntaxstr.format()メソッドのフォーマット指定子を参照してください。

14.1。 表現エラー

このセクションでは、「0.1」の例について詳しく説明し、このようなケースを自分で正確に分析する方法を示します。 バイナリ浮動小数点表現の基本的な知識があることを前提としています。

表現エラーは、一部の(ほとんどの場合)10進数の分数を2進数(基数2)の分数として正確に表現できないという事実を指します。 これが、Python(またはPerl、C、C ++、Java、Fortran、およびその他の多く)が期待する正確な10進数を表示しないことが多い主な理由です。

>>> 0.1 + 0.2
0.30000000000000004

何故ですか? 1/10と2/10は、2進分数として正確に表現できるわけではありません。 今日(2010年7月)のほとんどすべてのマシンはIEEE-754浮動小数点演算を使用しており、ほとんどすべてのプラットフォームがPython浮動小数点数をIEEE-754「倍精度」にマップしています。 754ダブルには53ビットの精度が含まれているため、入力時に、コンピューターは0.1を J / 2 ** N の形式で可能な最も近い分数に変換しようとします。ここで、 J [ X169X]は、正確に53ビットを含む整数です。 書き換え

1 / 10 ~= J / (2**N)

なので

J ~= 2**N / 10

J は正確に53ビット(>= 2**52ですが< 2**53)であることを思い出すと、 N の最適な値は56です。

>>> 2**52
4503599627370496
>>> 2**53
9007199254740992
>>> 2**56/10
7205759403792793

つまり、56は N の唯一の値であり、 J に正確に53ビットを残します。 J の可能な最良の値は、その商を四捨五入したものです。

>>> q, r = divmod(2**56, 10)
>>> r
6

余りは10の半分以上であるため、切り上げによって最良の近似値が得られます。

>>> q+1
7205759403792794

したがって、754倍精度で1/10に可能な最良の近似は、2 ** 56を超える、または

7205759403792794 / 72057594037927936

切り上げたので、これは実際には1/10より少し大きいことに注意してください。 切り上げていなかったとしたら、商は1/10より少し小さかったでしょう。 しかし、決して正確に 1/10になることはできません!

したがって、コンピュータは1/10を「認識」することはありません。認識されるのは、上記の正確な分数であり、取得できる最高の754二重近似です。

>>> .1 * 2**56
7205759403792794.0

その分数に10 ** 30を掛けると、その30の最上位10進数の(切り捨てられた)値を確認できます。

>>> 7205759403792794 * 10**30 // 2**56
100000000000000005551115123125L

これは、コンピューターに保存されている正確な数値が10進値0.100000000000000005551115123125にほぼ等しいことを意味します。 Python2.7およびPython3.1より前のバージョンでは、Pythonはこの値を有効数字17桁に丸め、「0.10000000000000001」を返しました。 現在のバージョンでは、Pythonは、真のバイナリ値に正しく丸められる最短の小数に基づいて値を表示し、結果は単に「0.1」になります。