ホームページ  >  記事  >  Java  >  Javaにおけるfloatと倍精度の損失の例の詳細な説明

Javaにおけるfloatと倍精度の損失の例の詳細な説明

零下一度
零下一度オリジナル
2017-06-28 11:38:431888ブラウズ

1.javaのint、float、long、doubleの値の範囲

[java] view plain copy

public class TestOutOfBound {

public static void main(String[] args) {

System.out . println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //メモリ オーバーフロー

System.out.println(Integer.MAX_VALUE) //2 の 31 乗、約 20 億お金を使うには十分ではないかもしれません

System.out.println(Integer.MIN_VALUE); // 負の 2 の 31 乗

System.out.println(Long.MAX_VALUE) // 2 の 64 乗 -1; 19 桁、非常に大きく、安心してお金に使用できます

System.out.println(Long.MIN_VALUE); //負の 2 の 64 乗

System.out.println(Float.MAX_VALUE ; - 149 乗

System.out.println(Double.MAX_VALUE); //2 の 1024 乗 -1,308 桁、float 桁数の 10 倍、主に複雑な演算と天文演算に使用されます

System.out .println( Double.MIN_VALUE); //2 の -1074 乗

}

}

2. 浮動小数点数と倍精度の損失の問題

例:

[java] プレーン コピーの表示

例: double result = 1.0 - 0.9;

言うまでもなく、この結果は誰もが知っています、0.099999999999999998

なぜこの問題が発生するのでしょうか? なぜこの問題が発生するのかを分析してみましょう。 :

float 型と double 型は主に科学計算と工学計算用に設計されています。これらは 2 進浮動小数点演算を実行します。この演算は、広範囲の数値に対して高精度で高速な近似計算を提供するように慎重に設計されています。ただし、完全に正確な結果が得られるわけではないため、正確な計算には使用しないでください。 float 型と double 型は、金融操作には特に適していません。float 型や double 型では、0.1 やその他の 10 の負のべき乗を正確に表すことができないためです (実際、理由は非常に単純です。10 進数で正確に表現できるかどうか)。 1/3 はどうですか? 同じ 2 進法では 1/10 を正確に表現できません。

浮動小数点演算が正確であることはほとんどなく、精度で表現できる範囲を超える限りエラーが発生します。多くの場合、エラーは数値のサイズが原因ではなく、数値の精度が原因で発生します。したがって、生成される結果は、望ましい結果に近いものではありますが、同じではありません。正確な演算に float と double を使用する場合は特に注意してください。

それでは、浮動小数点演算が精度の低下を引き起こす理由を詳しく分析してみましょう。



[java] view plain copy

まず、次の 2 つの質問を理解する必要があります:

(1) 10 進整数を 2 進数に変換する方法

アルゴリズムは非常に複雑です単純。たとえば、11はバイナリ数として表されます。

11/2 = 5 1

5/2 = 2以上11 の 2 進数表現は (下から上に): 1011

ここで 1 つ述べておきたいのは、割り算後の結果が 0 になった時点で終わりです。皆さん、考えてみてください。整数の割り算は本当ですか。 2で最終的には0になりますか?つまり、すべての整数を 2 進数に変換するアルゴリズムは無限ループを続けるのでしょうか。決してそうではありません。整数は常に 2 進数で正確に表現できますが、10 進数は必ずしも表現できるとは限りません。

(2) 10進数を2進数に変換する方法

このアルゴリズムは、小数がなくなるまで 2 を掛けます。たとえば、0.9 は 2 進数で表されます。 *2=1.6 整数部分 1 を取り出します

0.6*2=1.2 整数部分 1 を取り出します

0.2*2=0.4 整数部分 0 を取り出します

integerパート0

0. 0.8*2 = 1.6整数パート1を取ります

0.6*2 = 1.2整数パート0

0.9のバイナリ表現は(上から下まで): 1100100100100... 注: 上記の計算プロセスはループするため、*2 は小数部分を削除できないため、アルゴリズムは無限に継続されます。明らかに、10 進数の 2 進数表現を正確に行うことが不可能な場合があります。実は、その理由は非常に単純で、1/3 は 10 進法で正確に表現できるのでしょうか。同様に、2 進法では 1/10 を正確に表現できません。これは、浮動小数点減算に「無尽蔵の」精度損失の問題がある理由も説明します。

3. 解決策 1:

小数点を自分で記録することを気にせず、値が大きくない場合は、int を使用するかどうかに関係なく、long や int などの基本的な型を使用できます。範囲サイズの欠点は、小数点を自分で処理しなければならないことです。最も明白な方法は、通貨の計算に元ではなくセントを使用することです (加算と減算のみが必要です)。

例:

[java] view plain copy

int resultInt = 10 - 9;

double result = (double) resultInt / 100;//最終的には小数点を自分で制御します

4. 2:

BigDecmal を使用し、構築パラメーターで String 型を使用する必要があります。

「Effective Java」という本に解決策が記載されています。この本では、float と double は科学計算または工学計算にのみ使用できることも指摘されています。ビジネス計算などの精密な計算では、java.math.BigDecimal を使用する必要があります。


BigDecimal クラスには 4 つのメソッドがあります。私たちが注目するのは、浮動小数点データの正確な計算に役立つメソッド、つまり

BigDecimal(double value) // double データを BigDecimal データに変換する

このアイデアは非常に優れています。シンプルです。まず BigDecimal(double value) メソッドを使用して double データを BigDecimal データに変換します。その後、通常どおり正確な計算を実行できます。計算が完了したら、割り切れない結果を四捨五入するなど、結果に対して何らかの処理を行うことができます。最後に、結果は BigDecimal データから double データに変換されます。

この考えは正しいですが、API の BigDecimal の詳細な説明を詳しく見てみると、正確な計算が必要な場合は double を直接使用することはできず、BigDecimal を構築するために String を使用する必要があることがわかります。したがって、BigDecimal クラスの別のメソッド、つまり、正確な計算を正しく完了するのに役立つ BigDecimal(String value) メソッドに注目し始めます。

// BigDecimal(String value) は String データを BigDecimal データに変換できます

ここで問題が発生します。想像してみてください。浮動小数点データの加算演算を実行したい場合、最初に 2 つの浮動小数点数を文字列データに変換し、次に BigDecimal (文字列値) を使用して BigDecimal を構築する必要があります。次に、そのうちの 1 つで add メソッドを呼び出し、もう 1 つをパラメーターとして渡し、操作の結果 (BigDecimal) を浮動小数点数に変換します。浮動小数点データを計算するたびにこれを実行する必要がある場合、そのような面倒なプロセスに耐えることができますか?少なくとも私には無理です。したがって、最良の方法は、クラスを作成し、そのクラス内でこれらの面倒な変換プロセスを完了することです。このように、浮動小数点データの計算を実行する必要がある場合は、このクラスを呼び出すだけで済みます。インターネット上の一部の専門家は、これらの変換操作を完了するためのツール クラス Arith を提供してくれました。これは、浮動小数点データの加算、減算、乗算、および除算演算を完了し、結果を丸めることができる次の静的メソッドを提供します。

public static double add(double v1,double v2)
public static double sub(double v1) ,double v2 )
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,intscale)
public static doubleround(double v,int スケール)

Arith のソース コードを以下に添付します。浮動小数点計算を実行したい場合は、Arith クラスをソース プログラムにインポートするだけで、上記の静的メソッドを使用できます。浮動小数点計算を正確に実行します。

付録: Arith ソースコード

[java] view plain copy

import java.math.BigDecimal;

/**

* Java の単純型は浮動小数点数に対して正確な演算を実行できないため、このユーティリティ クラスは加算、減算、乗算、除算、丸めなどの正確な浮動小数点演算を提供します。

*/

public class Arith{

//デフォルトの除算演算精度

private static Final int DEF_DIV_SCALE = 10;

//このクラスはインスタンス化できません

private Arith(){

}

/**

* 正確な加算演算を提供します。

*/

public static double add (double v1, double v2) {

bigDecimal b1 = new bigDecimal (double.tostring (v1)); Turn B1.add (B2) .doubleValue() }

/**

* 正確な減算演算を提供します。

*/ public static double sub(double v1、double v2){bigdecimal b1 = new bigdecimal(v1)); double mul(double v1 ,double v2){

BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2));

return b1.multiply(b2).doubleValue();  

}

/**

* (比較的) 正確な除算演算を提供します。無尽蔵の除算が発生した場合、計算は

* 小数点以下 10 桁まで正確になり、それ以降の数値は四捨五入されます。

*/

public static double div(double v1,double v2){

return div(v1,v2,DEF_DIV_SCALE);  

}

/**

* (比較的) 正確な除算演算を提供します。無尽蔵除算が発生した場合、精度はスケールパラメータ

* で指定され、それ以降の数値は四捨五入されます。

*/

public static double div(double v1,double v2,int scale){

if(scale<0){

throw new IllegalArgumentException(

"スケールは正の整数またはゼロでなければなりません)。  

}

BigDecimal b1 = new BigDecimal(Double.toString(v1));  

BigDecimal b2 = new BigDecimal(Double.toString(v2));  

return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();  

}

/**

* 正確な小数点以下の四捨五入処理を提供します。

* @param v 四捨五入する必要がある数値

*/

public static double round(double v,int scale){

if(scale<0){

throw new IllegalArgumentException(

「スケールは必ず必要です」正の整数またはゼロであること)。  

}

BigDecimal b = new BigDecimal(Double.toString(v));  

BigDecimal one = new BigDecimal("1");  

return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();  

}

};  

以上がJavaにおけるfloatと倍精度の損失の例の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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