BigDecimal
实现精度运算的本质是,将小数转为去除小数点后的整数 + 小数点所在的位置
再进行相关整数运算,最后根据计算出来的整数跟小数点位置,加上小数点,进行返回
22.33 -> (2233, 2) 0.4 -> (4, 1) -> (40, 2) 22.33 + 0.4 = (2233, 2) + (40, 2) = (2273, 2) = 22.73
debug
查看 BigDecimal add()
的实现过程
// 测试用例 public class Test { public static void main(String[] args) { BigDecimal g = new BigDecimal("22.33"); System.out.println(g.add(new BigDecimal("0.4"))); } }
/** * 进行了删减,完整代码请自行查看 * new BigDcimal("22.33") new BigDecimal("0.4")实现过程 */ class BigDecimal { /** * 该 BigDecimal 的小数点所在位置 * new BigDcimal("22.33") -> scale = 2 * new BigDcimal("0.4") -> scale = 1 */ private final int scale; /** * 该 BigDecimal 的有效值位数(initCompact 的长度) * new BigDcimal("22.33") -> precision = 4 * new BigDcimal("0.4") -> precision = 1 */ private transient int precision; /** * 如果此 BigDecimal 有效位的绝对值小于或等于 Long.MaxValue, * 该值可以紧凑地存储在该字段中并用于计算。 * new BigDcimal("22.33") -> intCompact = 2233 * new BigDcimal("0.4") -> intCompact = 4 */ private final transient long intCompact; /** * new BigDecimal("22.33") 构造 */ public BigDecimal(String val) { // 将传过来的字符串,转为字符数组 // 22.33 -> ['2', '2', '.', '3', '3'] this(val.toCharArray(), 0, val.length()); } public BigDecimal(char[] in, int offset, int len) { this(in,offset,len,MathContext.UNLIMITED); } /** * 构造完成后,赋值全局属性 */ public BigDecimal(char[] in, int offset, int len, MathContext mc) { int prec = 0; // 记录 precision 的值 int scl = 0; // 记录 scale 的值 long rs = 0; // 记录 intCompact 的值 try { boolean dot = false; // 当为 '.' 的时候转为 true boolean isCompact = (len <= MAX_COMPACT_DIGITS); if (isCompact) { // ['2', '2', '.', '3', '3'] for (; len > 0; offset++, len--) { c = in[offset]; if ((c == '0')) { // 判断 0 是否是第一个值 (0.13 还是 1.03) if (prec == 0) prec = 1; else if (rs != 0) { // 数据进行累积 rs *= 10; ++prec; } // 检测到小数点后进行,小数点后位数的 累加 if (dot) ++scl; } else if ((c >= '1' && c <= '9')) { int digit = c - '0'; if (prec != 1 || rs != 0) ++prec; // 数据进行累积 rs = rs * 10 + digit; if (dot) ++scl; } else if (c == '.') { // 检测到小数点 if (dot) // 有两个小数点报错 throw new NumberFormatException("Character array" + " contains more than one decimal point."); dot = true; } } } } catch (ArrayIndexOutOfBoundsException | NegativeArraySizeException e) { NumberFormatException nfe = new NumberFormatException(); nfe.initCause(e); throw nfe; } // 赋值 this.scale = scl; this.precision = prec; this.intCompact = rs; } }
/** * ("22.33").add("0.4") 实现过程 */ class BigDecimal { public BigDecimal add(BigDecimal augend) { if (this.intCompact != Long.MIN_VALUE) { if ((augend.intCompact != Long.MIN_VALUE)) { // add(2233, 2, 4, 1) return add(this.intCompact, this.scale, augend.intCompact, augend.scale); } } } /** * (2233, 2, 4, 1) */ private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) { // 小数位后面数据的差值,sdiff = 1 long sdiff = (long) scale1 - scale2; if (sdiff == 0) { return add(xs, ys, scale1); } else if (sdiff < 0) { int raise = checkScale(xs,-sdiff); long scaledX = longMultiplyPowerTen(xs, raise); if (scaledX != Long.MIN_VALUE) { return add(scaledX, ys, scale2); } else { BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys); return ((xs^ys)>=0) ? // same sign test new BigDecimal(bigsum, INFLATED, scale2, 0) : valueOf(bigsum, scale2, 0); } } else { // raise = 1 int raise = checkScale(ys,sdiff); // scaledY = ys * 10^raise = ys * 10 = 40 long scaledY = longMultiplyPowerTen(ys, raise); if (scaledY != Long.MIN_VALUE) { // add(2233, 40, 2) return add(xs, scaledY, scale1); } else { BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs); return ((xs^ys)>=0) ? new BigDecimal(bigsum, INFLATED, scale1, 0) : valueOf(bigsum, scale1, 0); } } } /** * (2233, 40, 2) */ private static BigDecimal add(long xs, long ys, int scale){ // 2273 long sum = add(xs, ys); if (sum!=INFLATED) // BigDecimal.valueOf(2273, 2) -> new BigDecimal("22.73") return BigDecimal.valueOf(sum, scale); return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale); } }