ビット逆転テーブルの作り方
超小ネタ。
ウェーブレット行列の C++ 版を書いた時にビット逆転(上位から下位のビットの並びを逆にする)テーブルを作る必要があったので、その時にちょっと工夫したこと。どっかでとっくに既出かも。
状況としては、0 から 255 まで(8ビット)とか、0 から 1023 まで(10ビット)といった、ある最大ビット数を持つ数字に対してビット逆転テーブルを用意したいというもの。
それに対する実装。
bit_reverse_table_[0] = 0; for (uint64_t i = 0; i < alphabet_bit_num_; ++i) { uint64_t n = (1 << i); uint64_t m = (1 << (alphabet_bit_num_ - i - 1)); for (uint64_t j = 0; j < n; ++j) { bit_reverse_table_[n + j] = bit_reverse_table_[j] + m; } }
alphabet_bit_num_ がビット数、bit_reverse_table_ がビット逆転テーブル。
中身の解説。
まず、0 から 2^i-1 までのテーブルがすでにできているとする。
たとえば、alphabet_bit_num_=5, i=3 とすると、0 から 2^i-1=7 までのテーブル
00000 10000 01000 11000 00100 10100 01100 11100
までのものができている状態。
これを利用して、8 から 15 までのものを追加することを考える。
まず、8 から 15 という数字は、0 から 7 に 8 のところのビット(左から 2番目)を立てたものだ。
つまり、8 から 15 のビットを逆転させたものは、0 から 7 のビットを逆転させたものに 8 を逆転させたビット(右から 2 番目)を立てたものになる。
元々のテーブルに、右から 2番目のビットを立てたものを追加する。
00000 10000 01000 11000 00100 10100 01100 11100
00010 10010 01010 11010 00110 10110 01110 11110
これで、0 から 15 までのビットを逆転させたものができたことになる。
このように、0 から 2^i-1 までのテーブルがすでにできていれば、それにそれぞれ 1 個のビットを立てたものを追加するだけで、0 から 2^(i+1)-1 までのテーブルにできる。
で、最初に
bit_reverse_table_[0] = 0;
としていて、これが 0 から 2^0-1=0 までのテーブルということになる。
これで、帰納的に全部のテーブルが作れる。
まあ、どうせ作るテーブルの大きさなんてたいしたことないし、どう作っても一瞬だけど!
追記
テーブルを使わない場合は、http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel のような定番のものがありますが、テーブルを作る場合にこれを使うとちょっと無駄だと思います。まあ実用上問題になることはないと思いますが。
(2012/09/12 追記)
テーブルを使わない場合の例として、もっといいもの(by id:qnighy さん)があったのでリンク。ビットリバース - 簡潔なQ