源码中对其这样描述,
/**
* An immutable arbitrary-precision signed decimal.
*
* A value is represented by an arbitrary-precision "unscaled value" and a signed 32-bit "scale",
* combined thus: {@code unscaled * 10-scale}. See {@link #unscaledValue} and {@link #scale}.
*
*
Most operations allow you to supply a {@link MathContext} to specify a desired rounding mode.
*/
public class BigDecimal extends Number implements Comparable, Serializable {
“一个不可变的任意精度带符号的小数…”,内部提供了做加减乘除和数值的精度计算
在new创建对象的时候有如上这么多种选择方式传参,这里在计算的时候传入的对象类型不能为double类型,应当用string类型,不是string类型使用String.valueOf()转成string类型。看源码说明
主要看方法注释
/**
* Constructs a new {@code BigDecimal} instance from the 64bit double
* {@code val}. The constructed big decimal is equivalent to the given
* double. For example, {@code new BigDecimal(0.1)} is equal to {@code
* 0.1000000000000000055511151231257827021181583404541015625}. This happens
* as {@code 0.1} cannot be represented exactly in binary.
*
* To generate a big decimal instance which is equivalent to {@code 0.1} use
* the {@code BigDecimal(String)} constructor.
*
* @param val
* double value to be converted to a {@code BigDecimal} instance.
* @throws NumberFormatException
* if {@code val} is infinity or not a number.
*/
public BigDecimal(double val) {
if (Double.isInfinite(val) || Double.isNaN(val)) {
throw new NumberFormatException("Infinity or NaN: " + val);
}
long bits = Double.doubleToLongBits(val); // IEEE-754
long mantissa;
int trailingZeros;
// Extracting the exponent, note that the bias is 1023
scale = 1075 - (int)((bits >> 52) & 0x7FFL);
// Extracting the 52 bits of the mantissa.
mantissa = (scale == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1
: (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L;
if (mantissa == 0) {
scale = 0;
precision = 1;
}
// To simplify all factors '2' in the mantissa
if (scale > 0) {
trailingZeros = Math.min(scale, Long.numberOfTrailingZeros(mantissa));
mantissa >>>= trailingZeros;
scale -= trailingZeros;
}
// Calculating the new unscaled value and the new scale
if((bits >> 63) != 0) {
mantissa = -mantissa;
}
int mantissaBits = bitLength(mantissa);
if (scale < 0) {
bitLength = mantissaBits == 0 ? 0 : mantissaBits - scale;
if(bitLength < 64) {
smallValue = mantissa << (-scale);
} else {
BigInt bi = new BigInt();
bi.putLongInt(mantissa);
bi.shift(-scale);
intVal = new BigInteger(bi);
}
scale = 0;
} else if (scale > 0) {
// m * 2^e = (m * 5^(-e)) * 10^e
if(scale < LONG_FIVE_POW.length
&& mantissaBits+LONG_FIVE_POW_BIT_LENGTH[scale] < 64) {
smallValue = mantissa * LONG_FIVE_POW[scale];
bitLength = bitLength(smallValue);
} else {
setUnscaledValue(Multiplication.multiplyByFivePow(BigInteger.valueOf(mantissa), scale));
}
} else { // scale == 0
smallValue = mantissa;
bitLength = mantissaBits;
}
}
注释说因为double类型的数不能用二进制精确的表示,所以将数值转换为string做十进制运算。
BigDecimal number1 = new BigDecimal("11");
BigDecimal number2 = new BigDecimal("13.5");
BigDecimal add = number1.add(number2);
double v = add.doubleValue();
System.out.println("add = "+v);
结果为"add = 24.5"
BigDecimal number1 = new BigDecimal("11");
BigDecimal number2 = new BigDecimal("13.5");
BigDecimal add = number1.subtract(number2);
double v = add.doubleValue();
System.out.println("subtract = "+v);
结果为"subtract = -2.5"
BigDecimal number1 = new BigDecimal("11");
BigDecimal number2 = new BigDecimal("13.5");
BigDecimal add = number1.multiply(number2);
double v = add.doubleValue();
System.out.println("multiply = "+v);
结果为"multiply = 148.5"
BigDecimal number1 = new BigDecimal("10");
BigDecimal number2 = new BigDecimal("3");
BigDecimal add = number1.divide(number2,5,RoundingMode.DOWN);
double v = add.doubleValue();
System.out.println("divide = "+v);
// 这里解释一下number1.divide()方法的3个参数,
// 第一个参数是除数,
// 第二个参数是如果除不完保留几位小数,
// 最后一个参数是舍入模式,RoundingMode.DOWN为第二个参数后面的位数全部都舍去,不做四舍五入。
结果为“divide = 3.33333”
以下是源码RoundingMode类
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.math;
/**
* Specifies the rounding behavior for operations whose results cannot be
* represented exactly.
*/
public enum RoundingMode {
/**
* Rounding mode where positive values are rounded towards positive infinity
* and negative values towards negative infinity.
*翻译: 舍入模式,其中正值四舍五入正无穷,负值四舍五入负无穷
*
* Rule: {@code x.round().abs() >= x.abs()}
*/
UP(BigDecimal.ROUND_UP),
/**
* Rounding mode where the values are rounded towards zero.
* * 翻译:四舍五入模式,其中值四舍五入为零
*
* Rule: {@code x.round().abs() <= x.abs()}
*/
DOWN(BigDecimal.ROUND_DOWN),
/**
* Rounding mode to round towards positive infinity. For positive values
* this rounding mode behaves as {@link #UP}, for negative values as
* {@link #DOWN}.
* 翻译:四舍五入模式向正无穷四舍五入。对于正值,这种舍入模式表现为{@link #UP},对于负值,则表现为{@link #DOWN}。
*
* Rule: {@code x.round() >= x}
*/
CEILING(BigDecimal.ROUND_CEILING),
/**
* Rounding mode to round towards negative infinity. For positive values
* this rounding mode behaves as {@link #DOWN}, for negative values as
* {@link #UP}.
* 翻译:四舍五入模式向负无穷四舍五入。对于正值,这种舍入模式表现为{@link #DOWN},对于负值,则表现为{@link #UP}。
*
* Rule: {@code x.round() <= x}
*/
FLOOR(BigDecimal.ROUND_FLOOR),
/**
* Rounding mode where values are rounded towards the nearest neighbor. Ties
* are broken by rounding up.
* 翻译:舍入模式,将值舍入到最接近的邻居。 领带被四舍五入打破
*/
HALF_UP(BigDecimal.ROUND_HALF_UP),
/**
* Rounding mode where values are rounded towards the nearest neighbor. Ties
* are broken by rounding down.
* 翻译:舍入模式,将值舍入到最接近的邻居。 四舍五入关系被打破
*/
HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
/**
* Rounding mode where values are rounded towards the nearest neighbor. Ties
* are broken by rounding to the even neighbor.
* 翻译:舍入模式,将值舍入到最接近的邻居。 通过四舍五入来打平关系
*/
HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
/**
* Rounding mode where the rounding operations throws an ArithmeticException
* for the case that rounding is necessary, i.e. for the case that the value
* cannot be represented exactly.
* 翻译:舍入模式,在需要舍入的情况下,即在无法精确表示值的情况下,舍入操作会引发ArithmeticException
*/
UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
/** The old constant of BigDecimal
. */
private final int bigDecimalRM;
/** It sets the old constant. */
RoundingMode(int rm) {
bigDecimalRM = rm;
}
/**
* Converts rounding mode constants from class {@code BigDecimal} into
* {@code RoundingMode} values.
*
* @param mode
* rounding mode constant as defined in class {@code BigDecimal}
* @return corresponding rounding mode object
*/
public static RoundingMode valueOf(int mode) {
switch (mode) {
case BigDecimal.ROUND_CEILING:
return CEILING;
case BigDecimal.ROUND_DOWN:
return DOWN;
case BigDecimal.ROUND_FLOOR:
return FLOOR;
case BigDecimal.ROUND_HALF_DOWN:
return HALF_DOWN;
case BigDecimal.ROUND_HALF_EVEN:
return HALF_EVEN;
case BigDecimal.ROUND_HALF_UP:
return HALF_UP;
case BigDecimal.ROUND_UNNECESSARY:
return UNNECESSARY;
case BigDecimal.ROUND_UP:
return UP;
default:
throw new IllegalArgumentException("Invalid rounding mode");
}
}
}
第三个参数指定模式RoundingMode.UP也使用这种写法BigDecimal.ROUND_UP
number1.divide(number2,5,BigDecimal.ROUND_UP);
//BigDecimal.ROUND_DOWN;
//BigDecimal.ROUND_UP;
//BigDecimal.ROUND_CEILING;
//BigDecimal.ROUND_FLOOR;
//BigDecimal.ROUND_HALF_DOWN;
//BigDecimal.ROUND_HALF_EVEN;
//BigDecimal.ROUND_HALF_UP;
//BigDecimal.ROUND_UNNECESSARY;
//源码
...
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
return divide(divisor, scale, RoundingMode.valueOf(roundingMode));
}
...
//所以传入BigDecimal.ROUND_UP还是被转成了RoundingMode.UP
double value = new BigDecimal(String.valueOf(13.987)).setScale(2, BigDecimal.ROUND_UP).doubleValue();
DecimalFormat format = new DecimalFormat("#0.00");
System.out.println("decimal = " + format.format(value));
//结果为“decimal = 13.99”
//模式上面已经有说明可根据模式选择取舍
//创建DecimalFormat传入"#0.00"参数是因为想要保留两位小数,
//因为如果一个数的小数位如果是0的话,BigDecimal是不展示小数位0的