二重浮動小数点演算の精度が低下するのはなぜですか?

步履不停
リリース: 2019-07-06 09:58:20
オリジナル
4603 人が閲覧しました

二重浮動小数点演算の精度が低下するのはなぜですか?

まえがき: 仕事で、小数点を使った加減乗除の計算になると、BigDecimal を使って解決しようと考えますが、多くの人はその理由について混乱しています。 double または float は精度を失います。 BigDecimal を解決するにはどうすればよいでしょうか?さっそく始めましょう。

1. 浮動小数点数とは何ですか?

浮動小数点数は、コンピューターが科学表記法を使用して小数を表すために使用するデータ型です。 Java では、double は倍精度、64 ビット、浮動小数点数であり、デフォルトは 0.0d です。 float は単精度、32 ビットです。浮動小数点数、デフォルトは 0.0f;

二重浮動小数点演算の精度が低下するのはなぜですか?

メモリに格納

float 符号ビット (1 ビット) 指数 ( 8 ビット) 仮数部 (23 ビット)
double Sign ビット (1 ビット) 指数部 (11 ビット) 仮数部 (52 ビット)


メモリ内の浮動小数点の指数は、実際には指数であるため 8 ビットです。指数のフレームシフトの場合、指数の真の値が e で順序コードが E であると仮定すると、E=e (2^n-1 -1) となります。このうち、2^n-1 -1 は IEEE754 規格で規定されている指数オフセットであり、この式によれば 2^8 -1=127 となります。したがって、float の指数範囲は -128 127 ですが、double の指数範囲は -1024 1023 です。負の指数は浮動小数点数で表現できる最小の絶対値を持つ非ゼロの数値を決定し、正の指数は浮動小数点数で表現できる最大の絶対値を持つ数値を決定し、値の範囲も決定します。浮動小数点数の。


float の範囲は -2^128 ~ 2^127、つまり -3.40E 38 ~ 3.40E 38;
double の範囲は -2^1024 ~ 2^ 1023、また、それは -1.79E 308 ~ 1.79E 308

2. 歪みの科学的記数法を入力します

まず科学的記数法について話しましょう. 科学的記数法は、カウントを簡素化する方法です。非常に大きな数値または小さな数値を桁数の多い値で近似的に表現する場合、桁数の少ない値には科学的表記法の利点はありませんが、桁数の多い値については数え方の利点が得られます。は非常に明白です。たとえば、光の速度は 300000000 メートル/秒、世界の人口は約 6100000000 人です。光の速度や世界の人口のような大きな数値は読み書きに不便なので、光の速度は 3*10^8 として記述でき、世界の人口は 6.1*10^9 として記述できます。したがって、計算機は科学表記法を使用して、光の速度が 3E8 で、世界の人口が約 6.1E9 であることを示します。

私たちは子供の頃、狂ったように足したり引いたりするのが好きで電卓で遊んでいたのですが、最終的には電卓は下の図を表示しました。これは科学的表記法で表示された結果です。

二重浮動小数点演算の精度が低下するのはなぜですか?

#画像内の実際の値は -4.86*10^11=-486000000000 です。 10 進科学表記法では、有効数字の整数部分が [1, 9] の範囲内にある必要があります。

3. 歪みの精度を理解する

コンピューターがデータを処理する際には、データ変換や、さまざまな単位やさまざまな基数の変換など、さまざまな複雑な操作が必要になります。 (2進数10進数など)変換など、10÷3=3.3333…無限など割り算できない割り算が多く、精度に限界がある、3.3333333x3が複雑な処理後の小数である10に等しくないデータは正確ではありませんが、精度が高いほど正確になります。 float と double の精度は仮数部の桁数によって決まります。整数部分は常に暗黙の "1" であり、変更されないため、精度に影響を与えることはありません。 float: 2^23 = 8388608 計7桁 左端の桁が省略されているので、28388608 = 16777216 と8桁まで表現できることになります。有効数字は 8 桁ですが、必ず 7 桁であることが保証されており、float の精度は有効数字 7 ~ 8 桁、double: 2^52 = 4503599627370496 の合計 16 桁、同様に double の精度は16~17ビットです。

二重浮動小数点演算の精度が低下するのはなぜですか?

特定の値に達すると、科学表記法の使用が自動的に開始され、関連する精度の有効数字が保持されるため、結果は近似値となり、指数は整数になります。 10 進数では、一部の 10 進数は 2 進数で完全に表現できません。したがって、限られたビットでしか表現できないため、保存時にエラーが発生する可能性があります。 10 進数を 2 進数に変換するには、2 倍の方法を使用して計算し、整数部分を削除した後、小数部分がすべて 0 になるまで残りの小数を 2 倍します。

二重浮動小数点演算の精度が低下するのはなぜですか?

出力が 0.19999999999999998

という状況が発生した場合は、「0.3-0.1」と入力します。演算

0.3 * 2 = 0.6 => .0 (.6) で 0.3 をバイナリに変換し、0 を取り、0.6
0.6 * 2 = 1.2 => を残す必要があります。 .01 (. 2) 1 を取り、0.2
0.2 * 2 = 0.4 => .010 (.4) 0 を取り、0.4
0.4 * 2 = 0.8 => .0100 (.8) 0 を取り、0.8## を残します #0.8 * 2 = 1.6 => .01001 (.6) は 1 を取り、0.6 を残します
....

二重浮動小数点演算の精度が低下するのはなぜですか?

3. 概要

上記を読めば、浮動小数点数に精度の問題がある理由がおそらく明らかになるでしょう。簡単に言うと、float 型と double 型は主に科学計算と工学計算用に設計されており、広範囲の値に対してより正確かつ高速な近似和計算を提供するように慎重に設計された 2 進浮動小数点演算を実行します。ただし、完全に正確な結果が得られるわけではないため、正確な結果を得るために使用しないでください。特定のサイズに達した浮動小数点数は科学表記法を自動的に使用しますが、このような表現は実数の近似にすぎず、実数と同じではありません。 10 進数を 2 進数に変換するときに、無限ループや浮動小数点の仮数の長さの超過も発生する可能性があります。

4. では、BigDecimal を使用してそれを解決するにはどうすればよいでしょうか?

以下の 2 つの出力を見てください

二重浮動小数点演算の精度が低下するのはなぜですか?

##出力結果:

0.299999999999999988897769753748434595763683319091796875

0.3

に示すように、画像 Alibaba のコード制約プラグインは警告をマークし、String パラメーターのコンストラクター メソッドを使用して BigDecimal を作成するように求めてきました。 double は 0.3 (有限長のバイナリ) として正確に表現できないため、コンストラクターによって渡される値は 0.3 と正確には等しくありません。 BigDecimal を使用する場合は、String パラメーターのコンストラクター メソッドを使用して作成する必要があります。そういえば、BigDecimal の原理って何だろう、と疑問に思っている好奇心旺盛な赤ちゃんはいませんか?なぜ問題がないのでしょうか?実際、原理は非常に単純で、BigDecimal は不変であり、任意の精度の符号付き 10 進数を表すために使用できます。 double の問題は、小数点が 2 進数に変換され、精度が失われることです。 BigDecimal は、処理中に 10 進数を N 倍に拡張して、整数を計算できるようにし、対応する精度情報を保持します。 BigDecimal の保存方法については、ソースコードを参照してください。

よくある質問に関連する技術的な記事については、

FAQ 列にアクセスして詳細をご覧ください。

以上が二重浮動小数点演算の精度が低下するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート