Какой самый эффективный способ сделать побитовые операции в массиве C - PullRequest
10 голосов
/ 21 марта 2009

У меня есть массив C вроде:

char byte_array[10];

И еще один, который действует как маска:

char byte_mask[10];

Я хотел бы получить другой массив, который является результатом первого плюс второй, используя побитовую операцию для каждого байта.

Какой самый эффективный способ сделать это?

спасибо за ваши ответы.

Ответы [ 3 ]

14 голосов
/ 21 марта 2009
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];

(Конечно, вам нужен правильный тип для uint32_t, и если n не является степенью 2, вам нужно очистить начало и / или конец, чтобы выровнять 32-битный код.)

Вариация. Вопрос, в частности, требует размещения результатов в отдельном массиве, однако почти наверняка будет проще изменить входной массив на месте.

5 голосов
/ 21 марта 2009

Если вы хотите сделать это быстрее, убедитесь, что длина byte_array кратна 4 (8 на 64-битных машинах), а затем:

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, то вам, очевидно, нужно вместо этого сохранить результаты в другом массиве.)

1 голос
/ 21 марта 2009
\#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];
}

Попробуйте, код также может выглядеть чистым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...