何を、0.3から0.2≠0.1?

タグ:公共号の記事


歴史の痛みを伴う教訓

私は私たちに与えることを、見たことがなかった、まだ学校で覚えて、「オペレーションズリサーチを、」教師がテストコースを残し、それが私たちのそれぞれが、アルゴリズムの話の本を実現するようにすることです。当時、コックにコードを書く、脳のロジック内で詰めされたコードを書くかの全く階層、モジュラーコンセプトは完全に記述しても過言ではないではありません。

私はアルゴリズムを終了すると、我々はそれを行う方法を、入力値がいくつか正常にテストで見つけることができるよう、いくつかのテスト値を取得するために始めたが、一部ではありませんか?私は彼の首を回していない、2つの星のデバッグや試運転に全体の午後、プラス夜の時間を費やしたかのように聖歌をデバッグ、コードの大きな塊の混乱に直面し、デバッグは、単に災害で、本当に:一瞬のコードを記述するためにクール、デバッグ火葬場

最後に、私も不思議な現象を(また、後で心の中でレッスンを負担しなければならない)が見つかりました:

0.2 - 0.1 == 0.1この式の結果はtrue、しかし0.3 - 0.2 == 0.1、これは実際に式の結果であるがfalse、私は私の目を信じることができない、素直にドロップします。調査の後の調査では、本は不正確な方法は、この記事では、クラッククラックが来たか最後に、正確ではありません浮動小数点数のデジタル表現であると述べた〜

最終的にはどのように浮動小数点表現はありますか?

実際には、浮動小数点小数を示すために使用され、我々は通常、小数点以下を保存した後、バイナリコンピュータに変換することができます。例えば9.875、これは、小数のように表すことができます。

9.875 = 8 + 1 + 0.5 + 0.25 + 0.125 
      = 1 × 2³ + 1 × 2⁰ + 1 × 2⁻¹ + 1 × 2⁻² + 1 × 2⁻³ 
复制代码

言い換えれば、小数点以下場合9.875、バイナリ小数の単語には、次のとおりです1001.111コンピュータにそのようなバイナリ分数を格納するために、我々はそれらを統一がで発現a × 2ⁿ科学的表記の形、1≤|a|<2例えば、1001.111表現することができます1.001111 × 2³私たちは、小数点以下置く001111まで、仮数と呼ばれると呼ばれる指標、ちょうどこれらの部品の下に、小数点以下を表現するためにできるように、正と負の点の数は、存在するため。3

  • シンボルセクション。

  • 仮数部。

  • 指数部。

異なる記憶空間を表すことは仮数及び指数を用い、具体的に細分フロートです。

  • 単精度浮動小数点(float型の一般的なプログラミング言語):

    4バイトの単精度浮動小数点全

    • これは、0の符号ビット部分の値を使用して1の負の値を表す正の数を示す表現しました。

    • 8ビットを使用して指数部を表します。

    • 23ビットの仮数のセクションを使用します。

    概略図を描くことはこれです:

    image_1df37645t1v4mml1eo3t3u1v04m.png-78.2kB

  • 倍精度浮動小数点数(double型の一般的なプログラミング言語):

    8バイトの倍精度浮動小数点全

    • 1ビットは、シンボル区間で表されます。

    • 11ビットを使用して指数部を表します。

    • 52ビットの仮数のセクションを使用します。

    概略図が描かれていません。

科学技術、法律の使用のために直接それを終えられるデジタルマッピングに対応する位置に対応し、対応するインデックス番号と仮数部に、バイナリ割合を表しますか?例えば、二進分数のために1.001111 × 2³(すなわち、小数である9.875)、単精度浮動小数点で表される場合、それは(明確成分を表すために、我々は空間が各部分が実際には間隔はありません分離置く)このようにあるべきです。

0 00000011 00111100000000000000000
复制代码

どこで:

  • 最初のビットは0、これが正の数であることを示しています。

  • 00000011表現インデックス3

  • 00111100000000000000000仮数001111

ハハ、真実はそう単純ではない、いくつかの目的の叔父のためにフロートの設計(私たち人間が言うのは、この複合体がある)少し複雑に物事をもたらしました。彼らは文字通りの符号なしの量は、これはインデックスの本当の価値ではなく、コンピューティングのいくつかの紆余曲折の後、最終的な指標値を得るために意味、符号なし数として一部を指数部。彼らはフロートメモリーは議論の3種類に分けられます。

  • どちらのビットの指数部は、すべてゼロ(値0)ではない全て1(255、2047倍精度単精度)である場合:

    この場合、リテラルに等しいインデックス値のインデックスの実数部がオフセット値を減算する、いわゆる偏置值単精度浮動小数点である127倍精度浮動小数点で、1023

    我々は小数点2進小数単精度浮動小数点格納するのに使用したいとしましょう1.001111 × 2³、そのインデックス値を3、私たちはインデックスマイナスのリテラルの一部にする必要がある127値を3、そのインデックスのリテラルの一部である130バイナリでは、次のとおりです10000010仮数部は、001111それがバイナリ小数を表し、1.001111 × 2³真の単精度浮動小数点数です。

    0 10000010 00111100000000000000000
    复制代码

    ヒント:これは、髪ああのためにあるのですか?なぜ、リテラルに基づいて、いわゆるオフセット値を引くでしょう。実際には、設計は、指数のビットパイルを示すと考えられ、このようなフローティング叔父は、表現することができる桁数の合計は、8バイトの点の指数部をフローティング単精度例えば、決定され、次いでそれは、数字を表し、すなわち256の番号が、ビットがすべて0であると1特別な目的のためにすべての数値範囲であることができる2⁸の合計は、指数は127 -126で表すことができる最大254点の番号を表すことができます。これらは1 254デジタル最小を表すために、進数の最小量は00000001である符号無しデジタル顔としてたい、すなわち、-126であり、次いでリテラルとして増加し、それはインデックスの真値が徐々に表しますインデックス127の真の値を表すリテラル11111110の最大値まで、増加します。だからこの効果を達成することができますリテラルをもとに127を減算する必要があります。同様に、倍精度浮動小数点数のためにあなたは、インデックスの実際の値を取得するために1023の符号なしリテラルのインデックス部分の基礎を減算する必要があり、です。ちょうど大きいリテラルたい、フロートデザイン叔父を参照してください、指標の実際の値は、このの大きな目的は、オフセット値のこの奇妙な概念の導入でした。

  • 指数部のビットがすべて0である場合:

    これは特別なケースで、インデックスは、オフセット値を減算すると、単精度浮動小数点のために、1を表している、それは代表的な指標であり、この時点では0を表すものではありません1 - 127 = -126

    しかし、ケースはすでにのインデックス値表現されていない-126、まだ状況を、なぜこれのインデックス値なければならない-126場合は、それに白羽のですか?私たちは、からこれを持って1.001111 × 2³話して、このバイナリ分数の例では、我々は浮動小数点数が格納されているの仮数部であることを忘れないでください001111、自動的に小数点の左側を無視され、1これビットを節約し、。しかし、全体のインデックスの一部の場合には仮数部が1の左側に小数点が含まれていない、ゼロで、単精度浮動小数点数であると言います。

    0 00000000 01010000000000000000000
    复制代码

    このバイナリ10進浮動小数点表現は次のとおりです0.0101 × 2-¹²⁶

    ビット単精度浮動小数点仮数の部分が0である場合、の比で表されることが分かる1 × 2-¹²⁶番号0の部分に近い小さな数、すなわち、。

    浮動小数点の仮数部のビットがゼロである場合には、値を表すことができる0.0ので、そこに、(最初のビットである)が、符号ビットの存在+0.0-0.0点。

  • 両方のビットの指数部が1である場合:

    この時点では2例に細分化することができます。

    • 場合ビットの仮数部は0です。

      符号ビットが正の無限大を表し、0の場合この場合には無限大の値を表し、符号ビットが1である場合、負の無限大を表します。

    • 仮数部のビットがゼロでない場合。

      この場合表すNaN値を、NaN完全な名前は、数ではない、すなわち、いくつかの場合に有用である数を表すものではありません。

これまでのところ、浮動小数点ストレージNAGの3例が終了しました。あなたはパターンを発見した場合、私はその後、無記号の値が大きいほど、それは浮動小数点値を表し、符号ビットを考慮せずに、私たちは符号なしの浮動小数点数として残りのビットと仮定し、つまり、知りません大きなは、その操作の大きさの浮動小数点の比較を行うとき、それは非常にシンプルになります。

浮動小数点演算を見て

浮動小数点ストレージ・フォーマットを読んだ後、私たちは戻って、もともと提案を見て0.2 - 0.1 == 0.1true、および0.3 - 0.2 == 0.1時に値をfalseに。私たちの単精度浮動小数点数は、例えば、これらの表現は、これらの数値の表現にどのように関係するかを見てみましょう。

  • 0.1

    小数は0.1これだけ、近似値を丸めた後、バイナリ未満の端数が23で仮数に変身することはできません。

    1.10011001100110011001101 × 2⁻⁴
    复制代码

    インデックス値は-4、我々の最初のケースの上側に応じて、指数部がリテラルである123バイナリ分数として表現される01111011ので、我々は、小数を得ることができ0.1ている単精度浮動小数点数に対応します。

    0 01111011 10011001100110011001101
    复制代码
  • 0.2

    これはバイナリ分数の近似は次のとおりです。

    1.10011001100110011001101 × 2⁻³
    复制代码

    同様に、単精度浮動小数点を得ることができます

    0 01111100 10011001100110011001101
    复制代码
  • 0.3

    これはバイナリ分数の近似は次のとおりです。

    1.00110011001100110011010 × 2⁻²
    复制代码

    以下同様に、単精度浮動小数点を得ることができます。

    0 01111101 00110011001100110011010
    复制代码

その後:

  • 算出した0.2 - 0.1

    等価計算:

    1.10011001100110011001101 × 2⁻³ - 1.10011001100110011001101 × 2⁻⁴
    复制代码

    結果は次のとおりです。

    1.10011001100110011001101 × 2⁻⁴
    复制代码

    そして、これはちょうど10進値です0.1小数のバイナリ表現のは、その0.2 - 0.1 == 0.1式の結果ですtrue

  • 算出した0.3 - 0.2

    等価計算:

    1.00110011001100110011010 × 2⁻² - 1.10011001100110011001101 × 2⁻³
    复制代码

    結果は次のとおりです。

    1.10011001100110011001110 × 2⁻⁴
    复制代码

    そして、これには10進数ではありません0.1小数のバイナリ表現のため、0.3 - 0.2 == 0.1式の結果ですfalse

    この差は無限小数、二進小数を表すために使用される浮動小数点のストレージスペースを使用することが制限されなければならないしてもバイナリ画分に、主にバイナリ10進数小数点必要ビットのロットの結果丸め、バイナリ小数表現の結果が正確でない、ある程度、浮動小数点演算を使用するには正確ではありません、我々はプロセスで日常的に使用浮動小数点にもっと注意を払う必要があります。

余談

疲れ記事を書く、時にはあなたは、多くの修正の結果の後ろに実際にある非常に滑らかな読み取りを、感じます。あなたが良いと感じた場合は前方に助けてください、それ非常に感謝〜。ここで私のパブリック数時間から子牛を引い程度の時間に、内側より呉服技術「我々は小さなカエルです」、歓迎の注意:

おすすめ

転載: juejin.im/post/5d67656ff265da03d316d502