_BitScanReverse
や __builtin_clz
を使わないときの代替関数なので、やってることは clz (Count Leading Zeros)。■入力値の範囲が2^{32}
通り(32ビット)で出力値が32通り(5ビット)なので、ざっと2^{27}
分の1に情報が縮退している。■いちばんアホなアルゴリズムが2^{32}
通りの if 文を書くもので、人並みの知能があれば32通りの分岐を書いて済ませるくらいはできる。■ここからが魔術の出番。ビットの折りたたみ方次第ですべての入力値を分類して出力値のひとつへと導くことができる。■仕上げの “multiplication” で上位の5ビットに情報が集約されている。繰り上がりの有無が潜在的な分岐になっているのだろう。こういうのって『Hacker's Delight』を読んだら身に付くんだろうか。■clz の出力値の0っていうのは入力値の1ビット分の情報しか持っていないけど、1になると2ビット分。2になると……。畳み込まれている情報の量が違う。これは「パリティの計算(20170620)」と対照だと思う。だからどうってことではなくて、これ以上魔術に近づけないからお茶を濁してるってだけ。■■■PDF 読んだ。(1) 元の数を加工して MSB (most significant bit) だけが立った状態にする。数値としては2のべき乗になり、この数を掛けるということはシフト演算と同じ。(2) de Bruijn 列というのは文字種(k)と文字列長(n)の2つのパラメータで特徴付けられる長さk^n
の環状文字列(※末尾の次に先頭の文字が来ると考える)。パラメータに対してユニークではない。特徴は、長さ n の部分文字列を切り出したとき、どの2つとして同じものがないということ。例えば、長さ5のビット列を列挙するのに2^5=32
ビット長の de Bruijn 列を用意して、任意のビットから始めて5ビットを取り出せば足りるし、余りもしないということ。(3) 1 と 2 を組み合わせるとどうなるか。de Bruijn 列に(1)の値を掛けて、固定された位置にある幅 n のビット列を読み取ると、MSB に特有の値が得られる。de Bruijn 列を触媒にすることで 2^0
, 2^1
,...,2^{31}
だった値が、順不同ながら 0, 1,..., 31 という値に変換される。これこそが求める値。2のべき乗の掛け算(=左シフト)で仮想的にビット列を循環させるために、先頭の n ビットが 0 の de Bruijn 列を(2)で選んで、最上位の n ビットを部分列として読んでいる。■英語なのもあって一歩進むたびに「ん?」と置いて行かれそうになるんだけど、そのたびに “For example,...” と挙げられる具体例に助けられた。わかりやすい。最初から読んどけば良かった。■PDF ではこのアルゴリズムに対して、掛け算は遅い、メモリアクセス(テーブル引き)は遅い、64ビットの掛け算はもっと遅いという視点をもって性能評価を行っている。シビアだなあ。■■■@2019-07-09『ハッカーのたのしみ』に寄せられたガイ・L・スティール、ジュニアによる序文から。「2進数の加算と減算そしてことによるとビット単位の演算だけでできることは驚くほどである。キャリーの連鎖が単一のビットをその左側にある全ビットに影響させることができるという事実から、広く認識されていない形で、加算を特別強力なデータ操作演算にしている。」
Googleのように上司と部下全員が言語能力が高く、「論理的に正しいことは許容される」と分かっていれば、心理的安全はつくられやすいんです。年齢など関係なく、論理でぶつかり合い、正しいほうが勝つ。間違っていれば正される、だけですから。」 俺の理想がここにある。論理をぶつけ合えるほど同じ知的水準にあるとは言わないが、態度・姿勢だけでも見習いたい。■以前書いた。「「言い方が気に入らない」というような不満を、経験からの印象では、女の人からもれ聞くことがままあるように思う。(中略) 言い方はさておいても指摘の内容を真摯に受け止めることが自分のためになると思うんだがなあ。」■以前書いた。「感情に判断を左右されること、感情を満足させるために行動すること。精進が足りないと思う。」