在Integer類的源碼中,toString方法中調用getChars方法,getChars方法是獲取數值對應的字符串,其中有兩個地方使用了很是巧妙的方式來進行除法運算和取餘運算。在計算機中,a/b 和 a%b相比較位運算,都是比較費時的計算的。下面來看看jdk中是如何優化計算的git
// 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,直接除法ide
二、對100取餘:r = i - ((q << 6) + (q << 5) + (q << 2));
推導以下:
r = i - (q x 100)
r = i - (q x 64 + q x 32 + q x 4)
r = i - ((q << 6) + (q << 5) + (q << 2))優化
三、對10除法:q = (i x 52429) >>> (16+3);
推導以下:
2 >>> 19 爲 524288,
q = (52429 x i) / 524288 = (52428.8 x i + 0.2 x i) >>> (16+3),
i 拆分爲兩部分,i = a x 10 + b(保證a, b 均爲正數,且 0 <= b <= 9,
q = ((10a + b) x 52428.8 + 0.2b) >>> 19
q = (524288a + 52428.8b + 0.2i) >>> 19
其中,
52428.8b 最大值爲52428.8 x 9, 0.2i 最大值爲 13107.2
因此,
52428.8b + 0.2i 最大值爲 484966.4, 小於 524288 (1 >>> 19), 對應二進制會被右移掉
因此,
q = (a x 524288) >>> 19 + (52428.8 x b + i * 0.2) >>>19 = (a x 524288) >>> 524288 = acode
四、對10取餘:r = i - ((q << 3) + (q << 1));
推導以下:
r = i - (q x 10)
r = i - (q x 8 + q * 2)
r = i - ((q << 3 + q << 1)字符串
從這個方法咱們學到的get
一、乘法比除法高效:q = ( i 52429) >>> (16+3); => 約等於q0.1,但i52429是整數乘法器,結合位移避免除法
二、充分利用計算結果:在獲取r(i%100)時,充分利用了除法的結果,結合位移避免重複計算
三、位移比乘法高效:r = i – (( q << 6) + ( q << 5) + ( q << 2)); = >等價於r = i – (q 100)
四、局部性原理之空間局部性源碼