ICode9

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

BigDecimal类中的String参数类型的构造器(Java)

2021-09-27 10:36:24  阅读:205  来源: 互联网

标签:Java BigDecimal rs drop prec len offset 类中


JDK版本: JDK 8

构造方法

调用传入String类型的参数的构造器

public BigDecimal(String val) {
    this(val.toCharArray(), 0, val.length());
}

最终调用的是下面这个方法

/**
 * @param in      String类对象各单个字符组成的char数组
 * @param offset  初始为0
 * @param len     String对象的长度
 * @param mc      这里传入的是MaxContext.UNLIMITED, 不限制有效位数, 采用四舍五入
 */
public BigDecimal(char[] in, int offset, int len, MathContext mc)
查看构造器源码
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
        // protect against huge length.
        if (offset + len > in.length || offset < 0)
            throw new NumberFormatException("Bad offset or len arguments for char[] input.");
        // This is the primary string to BigDecimal constructor; all
        // incoming strings end up here; it uses explicit (inline)
        // parsing for speed and generates at most one intermediate
        // (temporary) object (a char[] array) for non-compact case.

        // Use locals for all fields values until completion
        int prec = 0;                 // 有效数字位数
        int scl = 0;                  // 小数点后有几位数
        long rs = 0;                  // the compact value in long
        BigInteger rb = null;         // the inflated value in BigInteger
        // use array bounds checking to handle too-long, len == 0,
        // bad offset, etc.
        try {
            // handle the sign
            boolean isneg = false;          // assume positive
            if (in[offset] == '-') {
                isneg = true;               // leading minus means negative
                offset++;
                len--;
            } else if (in[offset] == '+') { // leading + allowed
                offset++;
                len--;
            }

            // should now be at numeric part of the significand
            boolean dot = false;             // true when there is a '.'
            long exp = 0;                    // exponent
            char c;                          // current character
            boolean isCompact = (len <= MAX_COMPACT_DIGITS);
            // integer significand array & idx is the index to it. The array
            // is ONLY used when we can't use a compact representation.
            int idx = 0;
            if (isCompact) {
                // First compact case, we need not to preserve the character
                // and we can just compute the value in place.
                for (; len > 0; offset++, len--) {
                    c = in[offset];
                    if ((c == '0')) { // have zero
                        if (prec == 0)
                            prec = 1;
                        else if (rs != 0) {
                            rs *= 10;
                            ++prec;
                        } // else digit is a redundant leading zero
                        if (dot)
                            ++scl;
                    } else if ((c >= '1' && c <= '9')) { // have digit
                        int digit = c - '0';
                        if (prec != 1 || rs != 0)
                            ++prec; // prec unchanged if preceded by 0s
                        rs = rs * 10 + digit;
                        if (dot)
                            ++scl;
                    } else if (c == '.') {   // have dot
                        // have dot
                        if (dot) // two dots
                            throw new NumberFormatException();
                        dot = true;
                    } else if (Character.isDigit(c)) { // slow path
                        int digit = Character.digit(c, 10);
                        if (digit == 0) {
                            if (prec == 0)
                                prec = 1;
                            else if (rs != 0) {
                                rs *= 10;
                                ++prec;
                            } // else digit is a redundant leading zero
                        } else {
                            if (prec != 1 || rs != 0)
                                ++prec; // prec unchanged if preceded by 0s
                            rs = rs * 10 + digit;
                        }
                        if (dot)
                            ++scl;
                    } else if ((c == 'e') || (c == 'E')) {
                        exp = parseExp(in, offset, len);
                        // Next test is required for backwards compatibility
                        if ((int) exp != exp) // overflow
                            throw new NumberFormatException();
                        break; // [saves a test]
                    } else {
                        throw new NumberFormatException();
                    }
                }
                if (prec == 0) // no digits found
                    throw new NumberFormatException();
                // Adjust scale if exp is not zero.
                if (exp != 0) { // had significant exponent
                    scl = adjustScale(scl, exp);
                }
                rs = isneg ? -rs : rs;
                int mcp = mc.precision;
                int drop = prec - mcp; // prec has range [1, MAX_INT], mcp has range [0, MAX_INT];
                                       // therefore, this subtract cannot overflow
                if (mcp > 0 && drop > 0) {  // do rounding
                    while (drop > 0) {
                        scl = checkScaleNonZero((long) scl - drop);
                        rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
                        prec = longDigitLength(rs);
                        drop = prec - mcp;
                    }
                }
            } else {
                char coeff[] = new char[len];
                for (; len > 0; offset++, len--) {
                    c = in[offset];
                    // have digit
                    if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
                        // First compact case, we need not to preserve the character
                        // and we can just compute the value in place.
                        if (c == '0' || Character.digit(c, 10) == 0) {
                            if (prec == 0) {
                                coeff[idx] = c;
                                prec = 1;
                            } else if (idx != 0) {
                                coeff[idx++] = c;
                                ++prec;
                            } // else c must be a redundant leading zero
                        } else {
                            if (prec != 1 || idx != 0)
                                ++prec; // prec unchanged if preceded by 0s
                            coeff[idx++] = c;
                        }
                        if (dot)
                            ++scl;
                        continue;
                    }
                    // have dot
                    if (c == '.') {
                        // have dot
                        if (dot) // two dots
                            throw new NumberFormatException();
                        dot = true;
                        continue;
                    }
                    // exponent expected
                    if ((c != 'e') && (c != 'E'))
                        throw new NumberFormatException();
                    exp = parseExp(in, offset, len);
                    // Next test is required for backwards compatibility
                    if ((int) exp != exp) // overflow
                        throw new NumberFormatException();
                    break; // [saves a test]
                }
                // here when no characters left
                if (prec == 0) // no digits found
                    throw new NumberFormatException();
                // Adjust scale if exp is not zero.
                if (exp != 0) { // had significant exponent
                    scl = adjustScale(scl, exp);
                }
                // Remove leading zeros from precision (digits count)
                rb = new BigInteger(coeff, isneg ? -1 : 1, prec);
                rs = compactValFor(rb);
                int mcp = mc.precision;
                if (mcp > 0 && (prec > mcp)) {
                    if (rs == INFLATED) {
                        int drop = prec - mcp;
                        while (drop > 0) {
                            scl = checkScaleNonZero((long) scl - drop);
                            rb = divideAndRoundByTenPow(rb, drop, mc.roundingMode.oldMode);
                            rs = compactValFor(rb);
                            if (rs != INFLATED) {
                                prec = longDigitLength(rs);
                                break;
                            }
                            prec = bigDigitLength(rb);
                            drop = prec - mcp;
                        }
                    }
                    if (rs != INFLATED) {
                        int drop = prec - mcp;
                        while (drop > 0) {
                            scl = checkScaleNonZero((long) scl - drop);
                            rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
                            prec = longDigitLength(rs);
                            drop = prec - mcp;
                        }
                        rb = null;
                    }
                }
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new NumberFormatException();
        } catch (NegativeArraySizeException e) {
            throw new NumberFormatException();
        }
        this.scale = scl;
        this.precision = prec;
        this.intCompact = rs;
        this.intVal = rb;
    }

构造方法中的Character.isDigit(char c)

从源码中截取一部分代码,我们来看看Character.isDigit(char c)这个方法

查看代码
for (; len > 0; offset++, len--) {
    c = in[offset];
    if ((c == '0')) { // have zero
        if (prec == 0)
            prec = 1;
        else if (rs != 0) {
            rs *= 10;
            ++prec;
        } // else digit is a redundant leading zero
        if (dot)
            ++scl;
    } else if ((c >= '1' && c <= '9')) { // have digit
        int digit = c - '0';
        if (prec != 1 || rs != 0)
            ++prec; // prec unchanged if preceded by 0s
        rs = rs * 10 + digit;
        if (dot)
            ++scl;
    } else if (c == '.'){
        // 略
    } else if (Character.isDigit(c)) { // slow path
        int digit = Character.digit(c, 10);
        if (digit == 0) {
            if (prec == 0)
                prec = 1;
            else if (rs != 0) {
                rs *= 10;
                ++prec;
            } // else digit is a redundant leading zero
        } else {
            if (prec != 1 || rs != 0)
                ++prec; // prec unchanged if preceded by 0s
            rs = rs * 10 + digit;
        }
        if (dot)
            ++scl;
    }

当时在看这段代码时,不明白为什么在已经判断了字符是否为0~9,还要在后面调用Character.isDigit(char c)去判断是否是数字, 查看JDK8文档

Some Unicode character ranges that contain digits:
    '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') 
    '\u0660' through '\u0669', Arabic-Indic digits 
    '\u06F0' through '\u06F9', Extended Arabic-Indic digits 
    '\u0966' through '\u096F', Devanagari digits 
    '\uFF10' through '\uFF19', Fullwidth digits 

原来Unicode字符集中还有其他编码范围也是表示数字,做一下编码转换,这些数字如下

Arabic-Indic digits  '٠'  '١'  '٢'  '٣'  '٤'  '٥'  '٦'  '٧'  '٨'  '٩'
Extended Arabic-Indic digits    '۰'  '۱' '۲' '۳' '۴' '۵' '۶'  '۷'  '۸' '۹',  
Devanagari digits     '०' '१' '२' '३' '४' '५' '६' '७' '८' '९', 
Fullwidth digits     '0'    '1'   '2'   '3'   '4'   '5'   '6'   '7'   '8'  '9'

判断字符串是否是一个十进制数

调用BigDecimal的单个String参数的构造器方法,可以判断该字符串是否是数字

查看测试代码
import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        String[] strArr = {
                "123", "123.1", " 1.0", "123..1", "abc", 
                "1.1 ", "00.01", "001.01", "0101", "0x10"
        };
        for (String s : strArr) {
            try {
                BigDecimal bigDecimal = new BigDecimal(s);
                System.out.println(s + "是一个数字, 转换后的BigDecimal是" + bigDecimal);
            } catch (NumberFormatException e) {
                System.out.println(s + "不是一个数字");
            }
        }
    }
}
查看输出结果
123是一个数字, 转换后的BigDecimal是123
123.1是一个数字, 转换后的BigDecimal是123.1
 1.0不是一个数字
123..1不是一个数字
abc不是一个数字
1.1 不是一个数字
00.01是一个数字, 转换后的BigDecimal是0.01
001.01是一个数字, 转换后的BigDecimal是1.01
0101是一个数字, 转换后的BigDecimal是101
0x10不是一个数字

00.01 ,001.01 ,0101这三个数字也判断是数字,前置多余的零忽略去掉了

标签:Java,BigDecimal,rs,drop,prec,len,offset,类中
来源: https://www.cnblogs.com/coderzhiyi/p/15341773.html

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

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

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

ICode9版权所有