さっきjavaのIntegerのtoStringを読んだ。で、その過程で、IntegerのgetChars(int i, int index, char[] buf)の部分の実装(の一部)で感動したので、それを書く。あんまりjavaの話ではない。

感動した部分はこれの、

// 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];
}

ここ

    r = i - ((q << 6) + (q << 5) + (q << 2));


コメントから推測するに、どうやら、

((q << 6) + (q << 5) + (q << 2))

で q * 100 が計算できているようなのだが、最初意味がわからなかった。

まず、ほんとにそうなってるのかとりあえずirbで確認してみる。

irb(main):001:0> i = 65536
=> 65536
irb(main):002:0> (i << 6) + (i << 5) + (i << 2)
=> 6553600

やはり、100倍になっているようだ。

で、しばらく考えて、1ビットずらすということは、2倍するのと同じだったよなーと思う。そこで元の数字の2の6乗 + 2の5乗 + 2の2乗を足してみる。

irb(main):001:0> i = 65536
=> 65536
irb(main):002:0> (i * (2 ** 6)) + (i * (2 ** 5)) + (i * (2 ** 2))
=> 6553600

やはり、これで100倍になってるみたい。

ここで、やっと気がついて、iでくくってみる。すると

irb(main):001:0> i = 65536
=> 65536
irb(main):002:0> i * ((2 ** 6) + (2 ** 5) + (2 ** 2))
=> 6553600

おお。同じだ。

たしかに64 + 32 + 4は100だ。

ということで、やっぱりビット演算だけで100倍してるみたい。すげー、っていうお話。
普通に100倍するよりもやっぱりはやいのかなー。