ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript を超えて - プログラミングではなぜ同等ではないのか

JavaScript を超えて - プログラミングではなぜ同等ではないのか

DDD
DDDオリジナル
2024-09-13 22:17:02936ブラウズ

JavaScript は、開発者がこの一見不可解な結果に初めて遭遇したときに、頻繁に嘲笑されます。

0.1 + 0.2 == 0.30000000000000004

JavaScript による数値の処理に関するミームは広く広まっており、多くの人がこの動作はこの言語に特有のものであると信じています。

Beyond JavaScript - Why     doesn

ただし、この問題は JavaScript に限定されるものではありません。これは、ほとんどのプログラミング言語が浮動小数点演算を処理する方法の結果です。

たとえば、同様の結果を生成する JavaGo のコード スニペットを次に示します。

Beyond JavaScript - Why     doesn

Beyond JavaScript - Why     doesn

コンピュータはネイティブに整数のみを保存できます。彼らは分数を理解していません。 (どうやってやるのでしょうか? コンピューターが算術演算を行う唯一の方法は、ライトをオンまたはオフにすることです。ライトはオンでもオフでも構いません。「半分」オンにすることはできません!) 浮動小数点数を表現する何らかの方法が必要です。 。この表現は完全に正確ではないため、多くの場合、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 形式で数値を表す方法は次のとおりです。

Beyond JavaScript - Why     doesn

ここで、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 の表記:

Beyond JavaScript - Why     doesn

IEEE 754 それぞれ 0.1 と 0.2 の表記:

Beyond JavaScript - Why     doesn
Beyond JavaScript - Why     doesn

0.25 の場合の変換による誤差は 0 でしたが、0.1 と 0.2 にはゼロ以外の誤差があることに注意してください。

IEEE 754 では、浮動小数点数を表現するための次の形式が定義されています。

  • 単精度 (32 ビット): 符号に 1 ビット、指数に 8 ビット、仮数に 23 ビット

  • 倍精度 (64 ビット): 符号に 1 ビット、指数に 11 ビット、仮数に 52 ビット

話を簡単にするために、32 ビットを使用する単精度形式について考えてみましょう。

0.1 の 32 ビット表現は次のとおりです。

0 01111011 10011001100110011001101

Here the first bit represents the sign (0 which means positive in this case), the next 8 bits (01111011) represent the exponent and the final 23 bits (10011001100110011001101) represent the mantissa.

This is not an exact representation. It represents ≈ 0.100000001490116119384765625

Similarly, the 32 bit representation of 0.2 is:

0 01111100 10011001100110011001101

This is not an exact representation either. It represents ≈ 0.20000000298023223876953125

When added, this results in:

0 01111101 11001101010011001100110 

which is ≈ 0.30000001192092896 in decimal representation.

In conclusion, the seemingly perplexing result of 0.1 + 0.2 not yielding 0.3 is not an anomaly specific to JavaScript, but a consequence of the limitations of floating-point arithmetic across programming languages. The roots of this behaviour lie in the binary representation of numbers, which inherently leads to precision errors when handling certain fractions.

以上がJavaScript を超えて - プログラミングではなぜ同等ではないのかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。