C列にビット演算を行うための最も効率的な方法は何です最初の1つの結果から得られた別の配列と、ビットごとの演算を使用する2つ目の配列を各バイトで取得します。は、私のようなC配列を持つ
これを行う最も効率的な方法は何ですか?
あなたの答えに感謝します。後方プリロードプロセッサのキャッシュラインを行く
C列にビット演算を行うための最も効率的な方法は何です最初の1つの結果から得られた別の配列と、ビットごとの演算を使用する2つ目の配列を各バイトで取得します。は、私のようなC配列を持つ
これを行う最も効率的な方法は何ですか?
あなたの答えに感謝します。後方プリロードプロセッサのキャッシュラインを行く
for (i = 10 ; i-- > 0 ;)
result_array[i] = byte_array[i] & byte_mask[i];
これはすべてのアレイとプロセッサで機能します。ただし、配列がワード単位で配置されていることがわかっている場合、より高速な方法はより大きな型にキャストして同じ計算を行うことです。
たとえば、n=10
の代わりにn=16
とします。そして、これははるかに高速になります:
uint32_t* input32 = (uint32_t*)byte_array;
uint32_t* mask32 = (uint32_t*)byte_mask;
uint32_t* result32 = (uint32_t*)result_array;
for (i = 4 ; i-- > 0 ;)
result32[i] = input32[i] & mask32[i];
は(もちろん、あなたがuint32_t
のために適切な型を必要とし、n
が2のべき乗でない場合は、最初および/またはそのようエンディングをクリーンアップする必要があります32
バリエーション:この質問では、具体的には結果が別の配列に配置されることを要求していますが、入力配列をインプレースで変更することはほぼ確実に速くなります。
あなたはそれを速くしたい場合は、BYTE_ARRAYは(64ビットマシン上で8)4の倍数である長さを持っていることを確認して、次に:
char byte_array[12];
char byte_mask[12];
/* Checks for proper alignment */
assert(((unsigned int)(void *)byte_array) & 3 == 0);
assert(((unsigned int)(void *)byte_mask) & 3 == 0);
for (i = 0; i < (10+3)/4; i++) {
((unsigned int *)(byte_array))[i] &= ((unsigned int *)(byte_mask))[i];
}
これはそれにバイトをしているよりもはるかに高速であります1バイトあたり。
(これはインプレース変異であることに注意してください。あなたもオリジナルのBYTE_ARRAYを維持したい場合、あなたは明らかに代わりに別の配列に結果を格納する必要があります。)
\#define CHAR_ARRAY_SIZE (10)
\#define INT_ARRAY_SIZE ((CHAR_ARRAY_SIZE/ (sizeof (unsigned int)) + 1)
typedef union _arr_tag_ {
char byte_array [CHAR_ARRAY_SIZE];
unsigned int int_array [INT_ARRAY_SIZE];
} arr_tag;
今すぐマスキング用int_array。これは、32ビットプロセッサと64ビットプロセッサの両方で動作する可能性があります。
arr_tag arr_src, arr_result, arr_mask;
for (int i = 0; i < INT_ARRAY_SIZE; i ++) {
arr_result.int_array [i] = arr_src.int_array[i] & arr_mask.int_array [i];
}
これを試してみると、コードもきれいに見える場合があります。
サンプルコードを書いていただきありがとうございます:) – alvatar
キャッシュプリフェッチャが逆順で機能するのを待ちますか?私はそれが前進することを先取りするだけだと思った。 – Crashworks
プロセッサのキャッシュラインのプリロードについて心配するのは、早すぎる最適化のようです。 – Trent
@Trent - 質問の*ポイント*は最適化です。また後方に行くことも遅くないので、あなたもそうかもしれません。 @Crashworks - キャッシュラインは通常は大規模な境界に位置合わせされていることを覚えておいてください。通常は、要求する前にバイトをプルする必要があります。 –