開発者がこの一見不可解な結果に初めて遭遇したとき、JavaScript は頻繁に嘲笑されます:
0.1 0.2 == 0.30000000000000004
JavaScript による数値の処理に関するミームは広く普及しており、多くの人がこの動作はこの言語に特有のものであると信じています。
ただし、この問題は JavaScript に限定されるものではありません。これは、ほとんどのプログラミング言語が浮動小数点演算を処理する方法の結果です。
たとえば、同様の結果を生成する Java と Go のコード スニペットを次に示します。
コンピュータはネイティブに整数のみを保存できます。彼らは分数を理解していません。 (どうやってやるのでしょうか? コンピューターが算術演算を行う唯一の方法は、ライトをオンまたはオフにすることです。ライトはオンでもオフでも構いません。「半分」オンにすることはできません!) 浮動小数点数を表現する何らかの方法が必要です。 。この表現は完全に正確ではないため、多くの場合、0.1 0.2 は 0.3 と等しくなりません。
分母が基数の素因数で構成されるすべての分数は、他の分数が小数の繰り返しを持つ場合でも、きれいに表現できます。たとえば、基数 10 の記数法では、1/2、1/4、1/5、1/10 などの分数は、それぞれの場合の分母が 2 または 5 (10 の素因数) で構成されているため、きれいに表現されます。ただし、1/3、1/6、1/7 などの分数には循環小数が含まれます。
同様に、二進法では、1/2、1/4、1/8 などの分数はきれいに表現されますが、他のすべての分数には繰り返し小数が含まれます。これらの繰り返し小数の算術演算を実行すると、コンピューターの数値のバイナリ表現を人間が判読できる基数 10 の表現に変換するときに引き継がれる残りが生じます。これにより、ほぼ正しい結果が得られます。
この問題が JavaScript に限ったものではないことがわかったので、この動作が発生する理由を理解するために、浮動小数点数が内部でどのように表現および処理されるかを調べてみましょう。
浮動小数点数が内部でどのように表され処理されるかを理解するには、まず IEEE 754 浮動小数点標準を理解する必要があります。
IEEE 754 標準は、コンピュータ システムで浮動小数点数を表現および演算するために広く使用されている仕様です。これは、さまざまなコンピューティング プラットフォームで浮動小数点演算を使用する際の一貫性を保証するために作成されました。ほとんどのプログラミング言語とハードウェア実装 (CPU、GPU など) はこの標準に準拠しています。
これは、IEEE 754 形式で数値を表す方法です:
ここで、s は符号ビット (正の場合は 0、負の場合は 1)、M は仮数部 (数値の桁を保持)、E は、数値の位取りを決定する指数です。
この形式では、0.1、0.2、0.3 などの数値を正確に表すことができる M と E の整数値は見つかりません。最も近い結果を与える M と E の値のみを選択できます。
10 進数の IEEE 754 表記を決定するために使用できるツールは次のとおりです: https://www.h-schmidt.net/FloatConverter/IEEE754.html
IEEE 754 0.25 表記:
IEEE 754 それぞれ 0.1 と 0.2 の表記:
0.25 の場合の変換による誤差は 0 でしたが、0.1 と 0.2 ではゼロ以外の誤差があることに注意してください。
IEEE 754 では、浮動小数点数を表現するための次の形式が定義されています。
単精度 (32 ビット): 符号に 1 ビット、指数に 8 ビット、仮数に 23 ビット
倍精度 (64 ビット): 符号に 1 ビット、指数に 11 ビット、仮数に 52 ビット
簡単のために、32 ビットを使用する単精度形式を考えてみましょう。
0.1 の 32 ビット表現は次のとおりです:
0 01111011 10011001100110011001101
ここで、最初のビットは符号 (この場合は正を意味する 0) を表し、次の 8 ビット (01111011) は指数を表し、最後の 23 ビット (10011001100110011001101) は仮数を表します。
これは正確な表現ではありません。 ≈ 0.100000001490116119384765625
を表します。同様に、0.2 の 32 ビット表現は次のようになります。
0 01111100 10011001100110011001101
これも正確な表現ではありません。 ≈ 0.20000000298023223876953125
を表します。追加すると、次のようになります:
0 01111101 11001101010011001100110
これは、10 進数表現では ≈ 0.30000001192092896 です。
結論として、0.1 0.2 から 0.3 が得られないという一見当惑するような結果は、JavaScript に特有の異常ではなく、プログラミング言語全体にわたる浮動小数点演算の制限の結果です。この動作の原因は数値の 2 進表現にあり、特定の分数を処理するときに本質的に精度エラーが発生します。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3