回答:
A BigDecimal
は、数値を表す正確な方法です。A Double
には一定の精度があります。さまざまな大きさの倍精度(たとえばd1=1000.0
とd2=0.001
)0.001
を使用すると、大きさの差が非常に大きいため、合計すると全体がドロップされる可能性があります。これでBigDecimal
は起こりません。
の欠点BigDecimal
は、速度が遅くなることと、そのようにアルゴリズムをプログラムするのが少し難しくなることです(過負荷+
-
*
で/
ないため)。
お金を扱う場合、または精度が必要な場合は、を使用してくださいBigDecimal
。それ以外の場合Doubles
は十分に良い傾向があります。
ここで説明するよりも説明がよくなるので、javadocを読むことをお勧めBigDecimal
します:)
if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
BigDecimal
」と言うつもりだと思いますが、Doubleの方が「精度」が高くなります(桁数が多くなります)。
私の英語は下手なので、ここで簡単な例を書いてみます。
double a = 0.02;
double b = 0.03;
double c = b - a;
System.out.println(c);
BigDecimal _a = new BigDecimal("0.02");
BigDecimal _b = new BigDecimal("0.03");
BigDecimal _c = _b.subtract(_a);
System.out.println(_c);
プログラム出力:
0.009999999999999998
0.01
誰かがまだダブルを使いたいですか?;)
System.out.println(0.003f - 0.002f);
BigDecimalは正確です:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
doubleとの主な違いは2つあります。
金額の計算にBigDecimalを使用する必要がある理由は、任意の数値を表すことができるということではなく、10進表記で表すことができ、通貨の世界の実質的にすべての数値を含むすべての数値を表すことができることです(1/3 $を転送することはありません)誰かへ)。
小数値などの小数値を書き留める1 / 7
と、
1/7 = 0.142857142857142857142857142857142857142857...
無限のシーケンスで142857
。書き込むことができるのは有限の桁数だけなので、必然的に丸め(または切り捨て)エラーが発生します。
小数部のある2進数のような数値1/10
または1/100
2進数として表される数値も、小数点の後に桁数が無限にあります。
1/10 = binary 0.0001100110011001100110011001100110...
Doubles
値を2進数として格納するため、10進数を2進数に変換するだけでエラーが発生する可能性があります。
BigDecimal
一方、10進数(など)は、各10進数をそのまま格納します。つまり、10進数型は一般的な意味で2進浮動小数点または固定小数点型よりも正確ではありません(つまり1/7
、精度を失わずに格納することはできません)が、10進数の桁数が有限である数値の方が正確です。多くの場合、お金の計算に当てはまります。
JavaにBigDecimal
は、小数点の両側に任意の(ただし有限の)桁数があり、使用可能なメモリによってのみ制限されるという追加の利点があります。
BigDecimalは、Oracleの任意精度数値ライブラリです。BigDecimalはJava言語の一部であり、金融から科学的なものまでさまざまなアプリケーションに役立ちます(そういうところです)。
特定の計算にdoubleを使用しても何も問題はありません。ただし、Math.Pi * Math.Pi / 6、つまり2の実引数(現在取り組んでいるプロジェクト)のリーマンゼータ関数の値を計算したいとします。浮動小数点除算は、丸め誤差の痛い問題を引き起こします。
一方、BigDecimalには、任意の精度で式を計算するための多くのオプションが含まれています。BigDecimal Java Worldの+、*、および/の「代わりになる」以下のOracleドキュメントで説明されている加算、乗算、および除算メソッド:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
compareToメソッドは、whileおよびforループで特に役立ちます。
ただし、BigDecimalのコンストラクターの使用には注意してください。文字列コンストラクタは、多くの場合非常に役立ちます。たとえば、コード
BigDecimal onethird = new BigDecimal( "0.33333333333");
1/3の文字列表現を利用して、その無限に繰り返される数値を指定された精度で表します。丸めエラーは、JVMの非常に深い場所にある可能性が高く、丸めエラーが実際の計算のほとんどを妨げることはありません。しかしながら、私は個人的な経験から、四捨五入を見てきました。Oracleのドキュメントからわかるように、setScaleメソッドはこれらの点で重要です。
/* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
計算を扱う場合、計算方法と使用する精度に関する法律があります。失敗した場合、違法な行為をすることになります。唯一の真の理由は、小数のケースのビット表現が正確でないことです。バジルが単純に述べたように、例が最良の説明です。彼の例を補足するために、これがどうなるかです:
static void theDoubleProblem1() {
double d1 = 0.3;
double d2 = 0.2;
System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));
float f1 = 0.3f;
float f2 = 0.2f;
System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
}
出力:
Double: 0,3 - 0,2 = 0.09999999999999998
Float: 0,3 - 0,2 = 0.10000001
BigDec: 0,3 - 0,2 = 0.1
また、それがあります:
static void theDoubleProblem2() {
double d1 = 10;
double d2 = 3;
System.out.println("Double:\t 10 / 3 = " + (d1 / d2));
float f1 = 10f;
float f2 = 3f;
System.out.println("Float:\t 10 / 3 = " + (f1 / f2));
// Exception!
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
}
出力を提供します:
Double: 10 / 3 = 3.3333333333333335
Float: 10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
だが:
static void theDoubleProblem2() {
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
}
出力があります:
BigDec: 10 / 3 = 3.3333