BigDecimalを
精度の問題の損失の小数計算
コンピュータでは、すべてのファイルがバイナリに格納され、数クランチングは一切コンピュータが存在しないので、2進数、10進数ポイントを使用して計算し、私たちは通常のように浮いていると言うされfloat
、double
すべてのコンピュータがバイナリアナログを使用しますが、我々コンピュータを得られた結果は、次のコードを実行して正しくありません。
double a = 0.1;
double b = 0.3;
System.out.println(b-a);
// 结果为0.19999999999999998
なぜ?
私たちは二進数に小数を変換する方法を初めて目に
バイナリ分数0.1111
第一位1表示十进制1/2
第二位1表示十进制1/4
第三位1表示十进制1/8
第四位1表示十进制1/16
......
だから、小数点バイナリ分数を回し、アルゴリズムは、日付なし小数まで2乗算されます。たとえば、0.9は2進数を表します。
0.9*2=1.8 取整数部分 1
0.8(1.8的小数部分)*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 0
......... 0.9二进制表示为(从上往下): 1100100100100......
注:上記の計算サイクル、それは2が小数部分を排除することはできません*、このアルゴリズムは無限になりますです。もちろん、時には不可能正確な小数のバイナリ表現。実際には、その理由は、小数点システムは、まさにそれの1/3を非常に単純に表すことができないのですか?同じバイナリシステム1/10の正確な表現にすることはできません。これはまた、「マイナス無限の」精密損失の問題になぜ浮動小数点減算を説明しています。
BigDecimalの概要
精度の問題の損失なので、この問題を解決するためのJavaのBigDecimalクラスの導入ので。
BigDecimalの任意精度の整数スケールなしの値と32ビット整数のスケール(スケール)の組成物。ゼロ又は正の数であれば、スケールは小数点以下の桁数です。負の場合は、スケーリングされていない値が10スケールの負のパワーの数で乗算されます。したがって、のBigDecimalで表される値は、(unscaledValue 10規模を倍)です。
BigDecimalの機能紹介
コンストラクタ
コンストラクタ次のように
私たちは、のためにパラメータを使用するdouble
コードがあるから、次のようにオブジェクトを作成し、印刷するには、コンストラクタ
BigDecimal b1 =new BigDecimal(0.1);
System.out.println(b1);
//结果为0.1000000000000000055511151231257827021181583404541015625
私たちは、0.1の結果を楽しみにしてますが、その結果は、精度の損失となりました。BigDecimalのは、役に立たないですか?
次の文のBigDecimalを使用すると、精度に問題があるでしょう
BigDecimal b = new BigDecimal(0.1);
推奨使用方法
BigDecimal bd1 = new BigDecimal("0.1");
BigDecimal bd2 = BigDecimal.valueOf(0.1);
上記の方法は間違った精度の問題に行くことはありません使用して
ソースコードを知ることができます表示する)BigDecimal.valueOfを(、新しいBigDecimalを(「0.1」)コンストラクタを使用することです
JDKの説明:1、二重構造方式の結果の特定のパラメータタイプの予測不可能性。一つは、Javaで書かれた新しいBigDecimalを(0.1)は0.1とまったく同じである(スケールなしの値が1であり、そのスケールの1である)、それは実際に0.1000000000000000055511151231257827021181583404541015625に等しいBigDecimalをを作成することを考えるかもしれません。0.1が正確に二重(または、そのことについては、任意の有限長のバイナリ分数として表現することができない)のように表現することができないからです。この方法では、コンストラクタに渡される(この値は、上面に等しいが)0.1の値に正確に等しくありません。
2一方、Stringコンストラクタは完全に予測可能である:書くnewBigDecimal(「0.1」)予想0.1と正確に等しいBigDecimalのを作成します。したがって、対照的に、一般的にStringコンストラクタの優先順位を使用することをお勧めします。
最初持つDouble.toStringを使用して(二重)メソッドを、その後のBigDecimal(String)を使用します。それは以下の操作と同じ結果を提供しない、二重のBigDecimalが、この構成は、正確な変換方法を提供することに注意してください場合3、ソースが使用されなければなりません施工方法、文字列に二重。結果を得るために、静的のvalueOf(ダブル)メソッドを使用します。
一般的な方法
- 1.BigDecimal(文字列ヴァル):コンストラクタ、BigDecimalの文字列型のデータを変換します。
- 2.BigDecimal(ダブルヴァル):データを入力するdouble型に変換するコンストラクタ、BigDecimalを。
- 3.BigDecimal(int型のval):コンストラクタ、BigDecimalをint型データに変換します。
- 加算器、データとBigDecimalの二種類の和:(BigDecimal値)を追加4.BigDecimal。
- 5.BigDecimal減算(BigDecimal値):差し引き、差分のBigDecimalデータの2種類。
- 6.BigDecimal乗算(BigDecimal値):データの乗算、直交BigDecimalの二種類。
- 7.BigDecimal分割(BigDecimalを除数):分割、データプロバイダのBigDecimalの二種類を求めます。
- 8.BigDecimal残り(BigDecimalを除数):データのBigDecimalのタイプを求め、残りを見つけるは、除数で除算されます。
- 9.BigDecimal MAX(BigDecimal値):最大数、最大のBigDecimalは、データの2つのタイプを見つけます。
- 10.BigDecimalの分(BigDecimal値):最小数、データのBigDecimal最小の二種類の和。
- 11.BigDecimalのABS():絶対値、データ要求のBigDecimal型の絶対値。
- 12.BigDecimalネゲート():コントラストの数、BigDecimalの反対必要なデータの種類の数。
コードを示してい
BigDecimal a=new BigDecimal ("4.5");
BigDecimal b=new BigDecimal ("1.5");
BigDecimal c=new BigDecimal ("-10.5");
BigDecimal add_result=a.add(b);
BigDecimal subtract_result=a.subtract(b);
BigDecimal multiply_result=a.multiply(b);
BigDecimal divide_result=a.divide(b);
BigDecimal remainder_result=a.remainder(b);
BigDecimal max_result=a.max(b);
BigDecimal min_result=a.min(b);
BigDecimal abs_result=c.abs();
BigDecimal negate_result=a.negate();
Log.d("TAG","4.5+1.5="+add_result);
Log.d("TAG","4.5-1.5="+subtract_result);
Log.d("TAG","4.5*1.5="+multiply_result);
Log.d("TAG","4.5/1.5="+divide_result);
Log.d("TAG","4.5/1.5余数="+remainder_result);
Log.d("TAG","4.5和1.5最大数="+max_result);
Log.d("TAG","4.5和1.5最小数="+min_result);
Log.d("TAG","-10.5的绝对值="+abs_result);
Log.d("TAG","4.5的相反数="+negate_result);
結果
4.5+1.5=6.0
4.5-1.5=3.0
4.5*1.5=6.75
4.5/1.5=3
4.5/1.5余数=0.0
4.5和1.5最大数=4.5
4.5和1.5最小数=1.5
-10.5的绝对值=10.5
4.5的相反数=-4.5
BigDecimalのは不変(不変)で、操作のすべてのステップの間に、新しいオブジェクトを持つことになりますので、操作の値は、時に算術演算を保存しないことが決してありません。
BigDecimal
scale()
ような小数点以下の表現:
BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("1234500");
System.out.println(d1.scale()); // 2,两位小数
System.out.println(d2.scale()); // 4
System.out.println(d3.scale()); // 0
方法、0の終わりに等しいが、除去のフォーマット:BigDecimal
stripTrailingZeros()
BigDecimal
BigDecimal
BigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2,因为去掉了00
BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d1.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2
1た場合BigDecimal
のscale()
戻り負、例えば、-2、数が整数であることを示し、末端に2つのゼロがあります。
缶BigDecimal
設けられscale
、精度は、元の値よりも低い直接切り捨て又は丸め指定された方法に従った場合:
public class Main {
public static void main(String[] args) {
BigDecimal d1 = new BigDecimal("123.456789");
BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568
BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截断,123.4567
System.out.println(d2);
System.out.println(d3);
}
}
するにはBigDecimal
精度が失われていない場合に加算、減算、乗算を行うが、分裂を行い、ケースがあります分けることができない、そして、あなたは精度を指定する必要がありますし、どのようにカットします。
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
両者を比較するとBigDecimal
値を使用することに留意することが重要で、等しい場合equals()
方法は2つしか必要とBigDecimal
等しい値を、それらがまたために必要とされるscale()
等しくなります。
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600");
System.out.println(d1.equals(d2)); // false,因为scale不同
System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因为d2去除尾部0后scale变为2
System.out.println(d1.compareTo(d2)); // 0
使用しなければならないcompareTo()
2つの値の大きさ、0および正の、それぞれ、より大きい、より小さい、および同等によれば、それぞれ、ネガティブを返し、比較する方法。
必ず使用compareTo()
2つの比較するBigDecimal
値を、使用しないでくださいequals()
!
あなたが見ればBigDecimal
、ソースコード見つけることができ、実際にあるBigDecimal
ことにより、BigInteger
及びscale
示すために、そのBigInteger
完全な整数を表し、scale
小数点以下の桁数を表します。
public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal;
private final int scale;
}
BigDecimal
またからNumber
継承され、それは不変オブジェクトです。
ソースコード解析
なぜBigDecimal
使用はString
精度の問題が発生していない
と、今私たちは、なぜ使用することを理解しdouble
、floa
tは精度の問題が表示されます。今、私たちは見ていきますBigDecimal
文字列のための精度の問題がなかったです
コンストラクタによってデバッグは、我々は理解することができ、BigDecimalの基礎となるデータ構造は、主に以下の4つのプロパティ値で構成されています。
int scale; //有多少位小数(即小数点后有多少位)
int precision; //总工有多少位数字
long intCompact; //字符串去掉小数点后,转为long的值,只有当传的字符串长度小于18时才使用该言
BigInteger intVal; //当传的字符串长度大于等于18时才使用BigInteger表示数字
new BigDecimal("12.12")
例
scale值为2
precision值为4
intCompact值为1212
intVal值为空。
之所以为空是因为字符串长度没有超18位,所以不启用BigInteger表示
実際には、我々は理解しておく必要があります順番にこれを参照してください、BigDecimalのか、長いBigIntegerに文字列を計算すること。
valueOf(doubleval)メソッド
valueOf
実際には、適切なラッパークラスを呼び出すtoString
メソッドを、次いで、文字列オブジェクトのコンストラクタパラメータのBigDecimalを作成します。
(のBigDecimal被加数)を追加する方法
public BigDecimal add(BigDecimal augend) {
long xs = this.intCompact; //整型数字表示的BigDecimal,例a的intCompact值为122
long ys = augend.intCompact;//同上
BigInteger fst = (this.intCompact != INFLATED) ? null : this.intVal;//初始化BigInteger的值,intVal为BigDecimal的一个BigInteger类型的属性
BigInteger snd = (augend.intCompact != INFLATED) ? null : augend.intVal;
int rscale = this.scale;//小数位数
long sdiff = (long) rscale - augend.scale;//小数位数之差
if (sdiff != 0) {//取小数位数多的为结果的小数位数
if (sdiff < 0) {
int raise = checkScale(-sdiff);
rscale = augend.scale;
if (xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
fst = bigMultiplyPowerTen(raise);
} else {
int raise = augend.checkScale(sdiff);
if (ys == INFLATED || (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
snd = augend.bigMultiplyPowerTen(raise);
}
}
if (xs != INFLATED && ys != INFLATED) {
long sum = xs + ys;
if ((((sum ^ xs) & (sum ^ ys))) >= 0L)//判断有无溢出
return BigDecimal.valueOf(sum, rscale);//返回使用BigDecimal的静态工厂方法得到的BigDecimal实例
}
if (fst == null)
fst = BigInteger.valueOf(xs);//BigInteger的静态工厂方法
if (snd == null)
snd = BigInteger.valueOf(ys);
BigInteger sum = fst.add(snd);
return (fst.signum == snd.signum) ? new BigDecimal(sum, INFLATED, rscale, 0) :
new BigDecimal(sum, compactValFor(sum), rscale, 0);//返回通过其他构造方法得到的BigDecimal对象
}
これらは、BigIntegerのとのBigDecimalが不変(不変)であるため、最終的に新しいBigDecimalのオブジェクトを返し、実際にソースコード解析、減算、乗算、除算の単なる付加であり、動作の各ステップの間に、新たなオブジェクトを生成します従ってa.add(b)は、加算演算をしながら、しかし、動作を追加値を保持しない、正しい使用は= a.add(B)であるべきです。
概要
(1)ビジネス・コンピューティングのBigDecimalを使用します。
(2)タイプStringコンストラクタのパラメータを利用します。
(3)のBigDecimalは(不変)不変であり、動作の各ステップの間に、乗算と除算演算保存するために10万ドルの値を追加し、減算するように、新しいオブジェクトを生成します。
(4)私たちは、多くの場合、基礎となるJDKの実装の詳細の一部を見落とすことは容易、エラーになり、私たちはもっと注意を払う必要があります。