如何理解导致ArrayIndexOutOfBoundsException的mod计算的数学公式?

时间:2016-12-21 08:08:05

标签: java android math

[add]这不是关于ArrayIndexOutOfBoundsException的问题,纯粹是关于提醒计算算法,请不要将其标记为重复。

手机抛出ArrayIndexOutOfBoundsException,这是日志:

  

java.lang.ArrayIndexOutOfBoundsException:length = 36; index = 120 at   java.lang.IntegralToString.convertInt(IntegralToString.java:234)at at   java.lang.IntegralToString.appendInt(IntegralToString.java:173)at at   java.lang.StringBuilder.append(StringBuilder.java:139)at   android.telephony.SignalStrength.toString(SignalStrength.java:1123)at at   com.android.internal.telephony.ServiceStateTracker.onSignalStrengthResult(ServiceStateTracker.java:958)   在

异常发生在

  

buf [ - cursor] = DIGITS [r];

我的问题是如何理解代码,例如

  

int q =(int)((0x51EB851FL * i)>>> 37);

  

int q =(0xCCCD * i)>>> 19;

[delete]为什么不用int q = i / 10; int r = i - 10 * q;

[add]为什么int q =(0xCCCD * i)>>> 19;相当于int q = i / 10;

如果r是正确的,那么根据上述算法的评论,r如何为120。

以下是相关代码:

private static final char[] TENS = {
    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9'
};

/** Ones [i] contains the tens digit of the number i, 0 <= i <= 99. */
private static final char[] ONES = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
};
/**
 * The digits for every supported radix.
 */
private static final char[] DIGITS = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
    'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
    'u', 'v', 'w', 'x', 'y', 'z'
};

/**
     * Returns the string representation of i and leaves sb alone if sb is null.
     * Returns null and appends the string representation of i to sb if sb is non-null.
     */
    private static String convertInt(AbstractStringBuilder sb, int i) {
        boolean negative = false;
        String quickResult = null;
        if (i < 0) {
            negative = true;
            i = -i;
            if (i < 100) {
                if (i < 0) {
                    // If -n is still negative, n is Integer.MIN_VALUE
                    quickResult = "-2147483648";
                } else {
                    quickResult = SMALL_NEGATIVE_VALUES[i];
                    if (quickResult == null) {
                        SMALL_NEGATIVE_VALUES[i] = quickResult =
                                i < 10 ? stringOf('-', ONES[i]) : stringOf('-', TENS[i], ONES[i]);
                    }
                }
            }
        } else {
            if (i < 100) {
                quickResult = SMALL_NONNEGATIVE_VALUES[i];
                if (quickResult == null) {
                    SMALL_NONNEGATIVE_VALUES[i] = quickResult =
                            i < 10 ? stringOf(ONES[i]) : stringOf(TENS[i], ONES[i]);
                }
            }
        }
        if (quickResult != null) {
            if (sb != null) {
                sb.append0(quickResult);
                return null;
            }
            return quickResult;
        }

        int bufLen = 11; // Max number of chars in result
        char[] buf = (sb != null) ? BUFFER.get() : new char[bufLen];
        int cursor = bufLen;

        // Calculate digits two-at-a-time till remaining digits fit in 16 bits
        while (i >= (1 << 16)) {
            // Compute q = n/100 and r = n % 100 as per "Hacker's Delight" 10-8
            int q = (int) ((0x51EB851FL * i) >>> 37);
            int r = i - 100*q;
            buf[--cursor] = ONES[r];
            buf[--cursor] = TENS[r];
            i = q;
        }

        // Calculate remaining digits one-at-a-time for performance
        while (i != 0) {
            // Compute q = n/10 and r = n % 10 as per "Hacker's Delight" 10-8
            int q = (0xCCCD * i) >>> 19;
            int r = i - 10*q;
            buf[--cursor] = DIGITS[r];
            i = q;
        }

        if (negative) {
            buf[--cursor] = '-';
        }

        if (sb != null) {
            sb.append0(buf, cursor, bufLen - cursor);
            return null;
        } else {
            return new String(cursor, bufLen - cursor, buf);
        }
    }

1 个答案:

答案 0 :(得分:1)

  1. int q = (int) ((0x51EB851FL * i) >>> 37);
  2. 数字开头的

    0x表示该数字是以十六进制表示形式写的

    数字末尾的

    L表示该数字为Long - 已键入。这就是使用(int)投射的原因。

    >>>37表示此表达式左侧数字的二进制表示应向右移动37次。例如:

    16 >>> 2
    16 in binary is 10000.
    shift it to the right 2 times, we got 100.00
    100 in decimal system is equal to 4.
    16 >>> 2 = 4.
    
    1. int q = (0xCCCD * i) >>> 19;

    2. 相同
    3. 为什么不int q = i / 10; int r = i - 10q;

    4. IMO对十六进制数的移动比分割更加快速和精确。

      1. 如果r是正确的,那么根据上述算法的评论,r如何为120.
      2. 我很确定你可以在IDE中调试它以获得答案。