ビット文字列として解釈される MATLAB uint32 が与えられた場合、文字列に含まれる非ゼロ ビットの数を効率的かつ簡潔にカウントする方法は何ですか?
ビットをループする実用的で単純なアプローチがありますが、それは私のニーズには遅すぎます。(std::bitset count() を使用した C++ 実装はほぼ瞬時に実行されます)。
さまざまなビット カウント手法をリストしている非常に優れたページを見つけましたが、簡単な MATLAB 風の方法があることを願っています。
http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
更新 #1
Brian Kernighan アルゴリズムを次のように実装しました。
w = 0;
while ( bits > 0 )
bits = bitand( bits, bits-1 );
w = w + 1;
end
パフォーマンスは依然として悪く、4096^2 の重み計算を計算するのに 10 秒以上かかります。std::bitset の count() を使用する私の C++ コードは、これを 1 秒未満の時間で実行します。
アップデート #2
これまでに試した手法の実行時間の表を次に示します。追加のアイデアや提案があれば更新します。
ベクトル化されたシャイナー アルゴリズム => 2.243511 秒 ベクトル化された Naive bitget ループ => 7.553345 秒 カーニガン アルゴリズム => 17.154692 秒 length( find( bitget( val, 1:32 ) ) ) => 67.368278 秒 nnz( bitget( val, 1:32 ) ) => 349.620259 秒 Justin Scheiner のアルゴリズム、展開されたループ => 370.846031 秒 Justin Scheiner のアルゴリズム => 398.786320 秒 単純な bitget ループ => 456.016731 秒 合計 (dec2bin(val) == '1') => 1069.851993 秒
コメント: MATLAB の dec2bin() 関数は、実装が非常に不十分なようです。実行速度が非常に遅いです。
コメント: 「Naive bitget loop」アルゴリズムは次のように実装されています。
w=0;
for i=1:32
if bitget( val, i ) == 1
w = w + 1;
end
end
コメント: シャイナーのアルゴリズムのループ展開バージョンは次のようになります。
function w=computeWeight( val )
w = val;
w = bitand(bitshift(w, -1), uint32(1431655765)) + ...
bitand(w, uint32(1431655765));
w = bitand(bitshift(w, -2), uint32(858993459)) + ...
bitand(w, uint32(858993459));
w = bitand(bitshift(w, -4), uint32(252645135)) + ...
bitand(w, uint32(252645135));
w = bitand(bitshift(w, -8), uint32(16711935)) + ...
bitand(w, uint32(16711935));
w = bitand(bitshift(w, -16), uint32(65535)) + ...
bitand(w, uint32(65535));