問題は当然 O(n) であるため、ソリューションはおそらく最も効率的です。
ビットの任意のサブセットをカウントしようとしているため、ビットが設定されているときにビットをカウントすることはできません (ビットを頻繁に設定しないと、速度が向上します)。
使用しているプロセッサに、設定されたビット数を返すコマンドがあるかどうかを確認できます。たとえば、SSE4 を搭載したプロセッサは、この投稿に従ってPOPCNT を使用できます。.Net ではアセンブリが許可されていないため (プラットフォームに依存しないため)、これはおそらく機能しません。また、ARM プロセッサにはおそらく同等のものはありません。
おそらく最良の解決策は、ルックアップ テーブルです (または、スイッチが currentLocation + byteValue への単一のジャンプにコンパイルされることを保証できる場合はスイッチ)。これにより、バイト全体のカウントが得られます。もちろん、BitArray は基になるデータ型へのアクセスを提供しないため、独自の BitArray を作成する必要があります。また、バイト内のすべてのビットが常に交点の一部であることを保証する必要がありますが、これはありそうにありません。
もう 1 つのオプションは、BitArray の代わりにブール値の配列を使用することです。これには、バイト内の他のビットからビットを抽出する必要がないという利点があります。欠点は、配列がメモリ内の 8 倍のスペースを占有することです。つまり、スペースが無駄になるだけでなく、配列を反復処理してカウントを実行するときに、より多くのデータがプッシュされます。
標準の配列ルックアップと BitArray ルックアップの違いは次のとおりです。
配列:
- オフセット = インデックス * インデックスサイズ
- 位置 + オフセットでメモリを取得し、値に保存します
ビット配列:
- インデックス = インデックス/インデックス サイズ
- オフセット = インデックス * インデックスサイズ
- 位置 + オフセットでメモリを取得し、値に保存します
- 位置 = インデックス%indexSize
- シフト値位置ビット
- 値 = 値および 1
アレイの #2 と #3 を除いて、これらのコマンドのほとんどは、完了するのに 1 プロセッサ サイクルかかります。一部のコマンドは、x86/x64 プロセッサを使用して 1 つのコマンドに結合できますが、ARM では使用する命令セットが少ないため、おそらくそうではありません。
2 つ (アレイまたは BitArray) のどちらがより優れたパフォーマンスを発揮するかは、プラットフォーム (プロセッサ速度、プロセッサ命令、プロセッサ キャッシュ サイズ、プロセッサ キャッシュ速度、システム メモリの量 (Ram)、システム メモリの速度 (CAS)、速度) によって異なります。プロセッサと RAM の間の接続) と、カウントするインデックスの広がり (交点が最も頻繁にクラスター化されているか、ランダムに分散されているか)。
要約すると、おそらく高速化する方法を見つけることができますが、あなたのソリューションは、.NET のビットごとのブール モデルを使用してデータ セットを取得する最速のものです。
編集:順番に数えたいインデックスにアクセスしていることを確認してください。インデックス 200、5、150、151、311、6 の順にアクセスすると、キャッシュ ミスの量が増え、RAM から値が取得されるのを待つ時間が長くなります。