BigInteger源码学习

主要是String转int[]

/**
 * Translates the String representation of a BigInteger in the
 * specified radix into a BigInteger.  The String representation
 * consists of an optional minus or plus sign followed by a
 * sequence of one or more digits in the specified radix.  The
 * character-to-digit mapping is provided by {@code
 * Character.digit}.  The String may not contain any extraneous
 * characters (whitespace, for example).
 *
 * @param val String representation of BigInteger.
 * @param radix radix to be used in interpreting {@code val}.
 * @throws NumberFormatException {@code val} is not a valid representation
 *         of a BigInteger in the specified radix, or {@code radix} is
 *         outside the range from {@link Character#MIN_RADIX} to
 *         {@link Character#MAX_RADIX}, inclusive.
 * @see    Character#digit
 */
public BigInteger(String val, int radix) {
    int cursor = 0, numDigits;
    final int len = val.length();

    // radix 是否在2-36之间
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException("Radix out of range");
    if (len == 0)
        throw new NumberFormatException("Zero length BigInteger");

    // Check for at most one leading sign
    // 检查是否存在多个“+”“-”符号
    // 判断正负
    int sign = 1;
    int index1 = val.lastIndexOf('-');
    int index2 = val.lastIndexOf('+');
    if (index1 >= 0) {
        if (index1 != 0 || index2 >= 0) {
            throw new NumberFormatException("Illegal embedded sign character");
        }
        sign = -1;
        cursor = 1;
    } else if (index2 >= 0) {
        if (index2 != 0) {
            throw new NumberFormatException("Illegal embedded sign character");
        }
        cursor = 1;
    }
    if (cursor == len)
        throw new NumberFormatException("Zero length BigInteger");

    // Skip leading zeros and compute number of digits in magnitude
    // 忽略前置的0
    while (cursor < len &&
           Character.digit(val.charAt(cursor), radix) == 0) {
        cursor++;
    }

    // 字符串内全是0的情况,直接返回0值
    if (cursor == len) {
        signum = 0;
        mag = ZERO.mag;
        return;
    }

    numDigits = len - cursor;
    signum = sign;

    // 预分配预期大小的数组。可能太大,但决不可能太小。通常精确。
    long numBits = ((numDigits * bitsPerDigit[radix]) >>> 10) + 1;
    if (numBits + 31 >= (1L << 32)) {
        reportOverflow();
    }
    int numWords = (int) (numBits + 31) >>> 5;
    int[] magnitude = new int[numWords];

    // Process first (potentially short) digit group
    // 计算当前进制(radix)中,数组第一位保存的位数
    int firstGroupLen = numDigits % digitsPerInt[radix];
    if (firstGroupLen == 0)
        firstGroupLen = digitsPerInt[radix];
    String group = val.substring(cursor, cursor += firstGroupLen);
    magnitude[numWords - 1] = Integer.parseInt(group, radix);
    // 检查第一个值是否合法
    if (magnitude[numWords - 1] < 0)
        throw new NumberFormatException("Illegal digit");

    // 处理剩余的数字
    // 获取该进制最大位数
    int superRadix = intRadix[radix];
    int groupVal = 0;
    
    while (cursor < len) {
        group = val.substring(cursor, cursor += digitsPerInt[radix]);
        groupVal = Integer.parseInt(group, radix);
        if (groupVal < 0)
            throw new NumberFormatException("Illegal digit");
        // 向最后一位进行加法操作,再进行一次进位计算
        destructiveMulAdd(magnitude, superRadix, groupVal);
    }
    // Required for cases where the array was overallocated.
    // 去掉开头的0
    mag = trustedStripLeadingZeroInts(magnitude);
    if (mag.length >= MAX_MAG_LENGTH) {
        checkRange();
    }
}

/*
 * 整数模拟,对应radix(进制)的最大位数和指数方
 * intRadix = radix^digitsPerInt[radix]
 */
private static int digitsPerInt[] = {0, 0, 30, 19, 15, 13, 11,
    11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5};

private static int intRadix[] = {0, 0,
    0x40000000, 0x4546b3db, 0x40000000, 0x48c27395, 0x159fd800,
    0x75db9c97, 0x40000000, 0x17179149, 0x3b9aca00, 0xcc6db61,
    0x19a10000, 0x309f1021, 0x57f6c100, 0xa2f1b6f,  0x10000000,
    0x18754571, 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
    0x6c20a40,  0x8d2d931,  0xb640000,  0xe8d4a51,  0x1269ae40,
    0x17179149, 0x1cb91000, 0x23744899, 0x2b73a840, 0x34e63b41,
    0x40000000, 0x4cfa3cc1, 0x5c13d840, 0x6d91b519, 0x39aa400
};

// Multiply x array times word y in place, and add word z
// 计算低位是否需要向高增递交进位
private static void destructiveMulAdd(int[] x, int y, int z) {
    // Perform the multiplication word by word
    long ylong = y & LONG_MASK;
    long zlong = z & LONG_MASK;
    int len = x.length;

    long product = 0;
    long carry = 0;
    // 计算值后保存int值到数组中,再计算向高位递交的值
    for (int i = len-1; i >= 0; i--) {
        product = ylong * (x[i] & LONG_MASK) + carry;
        x[i] = (int)product;
        carry = product >>> 32;
    }

    // Perform the addition
    // 向最后一位进行加法操作,再进行一次进位计算
    long sum = (x[len-1] & LONG_MASK) + zlong;
    x[len-1] = (int)sum;
    carry = sum >>> 32;
    for (int i = len-2; i >= 0; i--) {
        sum = (x[i] & LONG_MASK) + carry;
        x[i] = (int)sum;
        carry = sum >>> 32;
    }
}

/**
 * Returns the input array stripped of any leading zero bytes.
 * Since the source is trusted the copying may be skipped.
 * 去掉开头的0
 */
private static int[] trustedStripLeadingZeroInts(int val[]) {
    int vlen = val.length;
    int keep;

    // Find first nonzero byte
    for (keep = 0; keep < vlen && val[keep] == 0; keep++)
        ;
    return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen);
}

在业务处理中,还遇到过要将char[]转成BigInteger的需求

/*
 * Constructs a new BigInteger using a char array with radix=10.
 * Sign is precalculated outside and not allowed in the val. The {@code val}
 * array is assumed to be unchanged for the duration of the constructor
 * call.
 * char[]数组,需要填写正负参数,只能定义10进制内容,还需要确定数组长度
 */
BigInteger(char[] val, int sign, int len) {
    int cursor = 0, numDigits;

    // Skip leading zeros and compute number of digits in magnitude
    while (cursor < len && Character.digit(val[cursor], 10) == 0) {
        cursor++;
    }
    if (cursor == len) {
        signum = 0;
        mag = ZERO.mag;
        return;
    }

    numDigits = len - cursor;
    signum = sign;
    // 预先估计数组大小
    int numWords;
    if (len < 10) {
        numWords = 1;
    } else {
        long numBits = ((numDigits * bitsPerDigit[10]) >>> 10) + 1;
        if (numBits + 31 >= (1L << 32)) {
            reportOverflow();
        }
        numWords = (int) (numBits + 31) >>> 5;
    }
    int[] magnitude = new int[numWords];

    // 处理第一位
    int firstGroupLen = numDigits % digitsPerInt[10];
    if (firstGroupLen == 0)
        firstGroupLen = digitsPerInt[10];
    magnitude[numWords - 1] = parseInt(val, cursor,  cursor += firstGroupLen);

    // 处理余下的
    while (cursor < len) {
        int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]);
        destructiveMulAdd(magnitude, intRadix[10], groupVal);
    }
    mag = trustedStripLeadingZeroInts(magnitude);
    if (mag.length >= MAX_MAG_LENGTH) {
        checkRange();
    }
}

long转BigInteger也是比较常见的

/**
 * 将long转成BigInteger,当数值大于int范围时,除以2^32,商为高位,地位直接转int格式
 */
private BigInteger(long val) {
    if (val < 0) {
        val = -val;
        signum = -1;
    } else {
        signum = 1;
    }

    int highWord = (int)(val >>> 32);// 除以2^32,获得进位
    if (highWord == 0) {
        mag = new int[1];
        mag[0] = (int)val;
    } else {
        mag = new int[2];
        mag[0] = highWord;
        mag[1] = (int)val;
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值