美文网首页探索JDK
探索Integer番外篇之Integer.getChars(in

探索Integer番外篇之Integer.getChars(in

作者: 苏小小北 | 来源:发表于2018-10-25 10:41 被阅读0次

    1. 前言


    在Integer类的源码中,toString方法中调用getChars方法,getChars方法是获取数值对应的字符串,其中有两个地方使用了非常巧妙的方式来进行除法运算和取余运算。在计算机中,a/b 和 a%b相比较位运算,都是比较费时的计算的。下面来看看jdk中是如何优化计算的

    2. 源码


    先lo代码:

            // Generate two digits per iteration
            while (i >= 65536) {
                q = i / 100;
            // really: r = i - (q * 100);
                r = i - ((q << 6) + (q << 5) + (q << 2));
                i = q;
                buf [--charPos] = DigitOnes[r];
                buf [--charPos] = DigitTens[r];
            }
            // Fall thru to fast mode for smaller numbers
            // assert(i <= 65536, i);
            for (;;) {
                q = (i * 52429) >>> (16+3);
                r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
                buf [--charPos] = digits [r];
                i = q;
                if (i == 0) break;
            }
            if (sign != 0) {
                buf [--charPos] = sign;
            }
    

    思路是这样:
    当 i >= 65536时,是每两位取出数字,i /= 100,例如 i = 567235474,
    (1)先取最后两位 7 和 4 放入buf数组中,i = 5672354,buf = { , , , , , , , '7', '4'};
    (2)再取最后两位 5 和 4 放入buf数组中,i = 56723,buf = { , , , , , '5', '4', '7', '4'};
    当 i < 65536 时,跳出循环,采用每一次取出一位数字,也就是 i /= 10
    (3)取最后一位 3 放入buf数组中,i = 5672,buf = { , , , , '3', '5', '4', '7', '4'};
    (4)取最后一位 2 放入buf数组中,i = 567,buf = { , , , '2', '3', '5', '4', '7', '4'};
    (5)取最后一位 7 放入buf数组中,i = 56,buf = { , , '7', '2', '3', '5', '4', '7', '4'};
    (6)取最后一位 6 放入buf数组中,i = 5,buf = { , '6', '7', '2', '3', '5', '4', '7', '4'};
    (7)取最后一位 5 放入buf数组中,i = 0,buf = { '5', '6', '7', '2', '3', '5', '4', '7', '4'},结束。
    但在jdk中,并不都是直接用 a/b 除法 和 a%c 取余来获取 商 和 余数的

    • 对100除法:q = i / 100,直接除法
    • 对100取余:r = i - ((q << 6) + (q << 5) + (q << 2));
      推导如下:
             r = i - (q * 100)
             r = i - (q * 64 + q * 32 + q * 4)
             r = i - ((q << 6) + (q << 5) + (q << 2))
    • 对10除法:q = (i * 52429) >>> (16+3);
      推导如下:
             2 >>> 19 为 524288,
             q = (52429i) / 524288 = (52428.8i + 0.2i) >>> (16+3),
      i 拆分为两部分,i = a * 10 + b(保证a, b 均为正数,且 0 <= b <= 9,
             q = ((10
      a+b) * 52428.8 + 0.2b) >>> 19
             q = (524288
      a + 52428.8b + 0.2i) >>> 19
      其中,
             52428.8b 最大值为52428.8 * 9, 0.2i 最大值为 13107.2
      所以,
             52428.8b + 0.2i 最大值为 484966.4, 小于 524288 (1 >>> 19), 对应二进制会被右移掉
      所以,
              q = (a * 524288) >>> 19 + (52428.8 * b + i * 0.2) >>>19 = (a*524288) >>> 524288 = a
    • 对10取余:r = i - ((q << 3) + (q << 1));
      推导如下:
             r = i - (q * 10)
             r = i - (q * 8 + q * 2)
             r = i - ((q << 3 + q << 1)

    后言


    是不是很有意思,以后除法或者是取余运算,你还只是会用 “/”, “%”了吗

    其他

    本人也是在慢慢学习中,如有错误还请原谅、敬请指出,谢谢!

    相关文章

      网友评论

        本文标题:探索Integer番外篇之Integer.getChars(in

        本文链接:https://www.haomeiwen.com/subject/hecqtqtx.html