更新: この回答は、私のコメントが以下のソース コードと一致するように変更されました。
SSE2 および popcnt 命令を使用できる場合は、最適化を利用できます。
たまたま 16 バイトが SSE レジスタにうまく収まります。C++ とアセンブリ/組み込み関数を使用して、2 つの 16 バイト配列を xmm レジスタにロードし、それらを cmp します。これにより、比較の真/偽の条件を表すビットマスクが生成されます。次に、movmsk 命令を使用して、ビットマスクのビット表現を x86 レジスタにロードします。これはビット フィールドになり、すべての 1 を数えて真の値がいくつあるかを判断できます。ハードウェア popcnt 命令は、レジスタ内のすべての 1 をすばやくカウントする方法です。
これには、特にアセンブリ/組み込み関数と SSE の知識が必要です。両方の Web リソースを見つけることができるはずです。
SSE2 も popcnt もサポートしていないマシンでこのコードを実行する場合は、配列を繰り返し処理し、アンロール ループ アプローチで差異をカウントする必要があります。
幸運を
編集:あなたはアセンブリを知らなかったと述べたので、私の答えを説明するサンプルコードを次に示します。
#include "stdafx.h"
#include <iostream>
#include "intrin.h"
inline unsigned cmpArray16( char (&arr1)[16], char (&arr2)[16] )
{
__m128i first = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr1 ) );
__m128i second = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr2 ) );
return _mm_movemask_epi8( _mm_cmpeq_epi8( first, second ) );
}
int _tmain( int argc, _TCHAR* argv[] )
{
unsigned count = 0;
char arr1[16] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 };
char arr2[16] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 };
count = __popcnt( cmpArray16( arr1, arr2 ) );
std::cout << "The number of equivalent bytes = " << count << std::endl;
return 0;
}
いくつかのメモ: この関数は、SSE2 命令と、Phenom プロセッサ (私が使用しているマシン) に導入された popcnt 命令を使用します。SSE4 を搭載した最新の Intel プロセッサにも popcnt があると思います。この関数は、CPUID による命令のサポートをチェックしません。SSE2 または popcnt を備えていないプロセッサで使用した場合、関数は未定義です (無効な opcode 命令を取得する可能性があります)。その検出コードは別のスレッドです。
私はこのコードの時間を計測していません。高速だと思う理由は、ブランチレスで一度に 16 バイトを比較するためです。これを自分の環境に合わせて変更し、それが機能するかどうかを自分で時間をかけて確認してください。私はVS2008 SP1でこれを書いてテストしました。
SSE は、自然な 16 バイト境界に整列されたデータを優先します。追加の速度向上が得られることを保証できれば、_mm_loadu_si128 命令を _mm_load_si128 に変更できます。これにはアライメントが必要です。