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);
}
}