10

次のようなC配列があります。

char byte_array[10];

そして、マスクとして機能する別のもの:

char byte_mask[10];

各バイトで、ビットごとの操作を使用して、最初の配列と2番目の配列の結果である別の配列を取得したいと思います。

これを行う最も効率的な方法は何ですか?

回答ありがとうございます。

4

3 に答える 3

15
for ( i = 10 ; i-- > 0 ; )
    result_array[i] = byte_array[i] & byte_mask[i];
  • 逆方向に進むと、プロセッサーのキャッシュラインがプリロードされます。
  • 比較にデクリメントを含めると、いくつかの命令を節約できます。

これは、すべてのアレイとプロセッサで機能します。ただし、配列がワード アラインされていることがわかっている場合は、より高速な方法は、より大きな型にキャストして同じ計算を行うことです。

たとえば、n=16代わりにn=10. 次に、これははるかに高速になります。

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];

(もちろん、 には適切な型が必要です。 が 2 の累乗でないuint32_t場合nは、32 ビットのものを揃えるために、先頭と末尾をクリーンアップする必要があります。)

バリエーション: この質問は、結果を別の配列に配置することを具体的に要求していますが、入力配列をインプレースで変更する方がほぼ確実に高速です。

于 2009-03-20T22:53:38.350 に答える
5

より高速にしたい場合は、byte_array の長さが 4 の倍数 (64 ビット マシンでは 8) であることを確認してから、次のようにします。

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];
}

これは、バイトごとに実行するよりもはるかに高速です。

(これはインプレース ミューテーションであることに注意してください。元の byte_array も保持したい場合は、代わりに結果を別の配列に格納する必要があることは明らかです。)

于 2009-03-20T22:55:58.080 に答える
1
\#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];
}

これを試してみてください。コードもきれいに見えるかもしれません。

于 2009-03-21T01:05:08.597 に答える