ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

BigDemical add 源码分析

2022-03-10 11:35:45  阅读:134  来源: 互联网

标签:BigDemical BigDecimal int add 源码 xs new ys


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

标签:BigDemical,BigDecimal,int,add,源码,xs,new,ys
来源: https://www.cnblogs.com/Kevin-QAQ/p/15988716.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有