问题:new BigDecimal(double d)的数值居然还是不精确的
double d = 0.09;
BigDecimal bigDecimal=new BigDecimal(d);
System.out.println(bigDecimal);
System.out.println(d);
输出结果:
0.0899999999999999966693309261245303787291049957275390625
0.09
原因:BigDecimal将double数据转换成为long bits,进行移位计算数值,而double的long bits移位计算是无法得到0.09的精确数值,所有造成数据精度丢失。
为了避免丢失double的数据精度,将double数据转成String,使用BigDecimal(String s)构造方法。
public class BigDecimal extends Number implements Comparable<BigDecimal>{public BigDecimal(double val) {this(val,MathContext.UNLIMITED);}public BigDecimal(double val, MathContext mc) {if (Double.isInfinite(val) || Double.isNaN(val))throw new NumberFormatException("Infinite or NaN");// Translate the double into sign, exponent and significand, according// to the formulae in JLS, Section 20.10.22.long valBits = Double.doubleToLongBits(val);int sign = ((valBits >> 63) == 0 ? 1 : -1);int exponent = (int) ((valBits >> 52) & 0x7ffL);long significand = (exponent == 0? (valBits & ((1L << 52) - 1)) << 1: (valBits & ((1L << 52) - 1)) | (1L << 52));exponent -= 1075;// At this point, val == sign * significand * 2**exponent./** Special case zero to supress nonterminating normalization and bogus* scale calculation.*/if (significand == 0) {this.intVal = BigInteger.ZERO;this.scale = 0;this.intCompact = 0;this.precision = 1;return;}// Normalizewhile ((significand & 1) == 0) { // i.e., significand is evensignificand >>= 1;exponent++;}int scale = 0;// Calculate intVal and scaleBigInteger intVal;long compactVal = sign * significand;if (exponent == 0) {intVal = (compactVal == INFLATED) ? INFLATED_BIGINT : null;} else {if (exponent < 0) {intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);scale = -exponent;} else { // (exponent > 0)intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal);}compactVal = compactValFor(intVal);}int prec = 0;int mcp = mc.precision;if (mcp > 0) { // do roundingint mode = mc.roundingMode.oldMode;int drop;if (compactVal == INFLATED) {prec = bigDigitLength(intVal);drop = prec - mcp;while (drop > 0) {scale = checkScaleNonZero((long) scale - drop);intVal = divideAndRoundByTenPow(intVal, drop, mode);compactVal = compactValFor(intVal);if (compactVal != INFLATED) {break;}prec = bigDigitLength(intVal);drop = prec - mcp;}}if (compactVal != INFLATED) {prec = longDigitLength(compactVal);drop = prec - mcp;while (drop > 0) {scale = checkScaleNonZero((long) scale - drop);compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);prec = longDigitLength(compactVal);drop = prec - mcp;}intVal = null;}}this.intVal = intVal;this.intCompact = compactVal;this.scale = scale;this.precision = prec;}
}