как сделать логическое ИЛИ памяти области, указанной массивом - PullRequest
0 голосов
/ 03 ноября 2011

Если предположить, что имеется два массива a [N], b [N], содержащих только значения 0 и 1, существует ли способ вычисления c = a ||b без цикла, подобного следующему (в C)?

#define N 10
char a[N];
char b[N];
char c[N];


// suppose to do some operations on a and b so that 
// for each i a[i] == 0 or a[i] == 1
// and the same for b

// this is the loop i would want to avoid
int i;
for(i=0;i<N;i++)
     c[i] = a[i] || b[i];

Я бы хотел вычислить результат (a || b), непосредственно сравнивая две области памяти, но я не знаю, если этовозможный.Большое спасибо за ваше внимание.

Ответы [ 6 ]

4 голосов
/ 03 ноября 2011

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

Редактировать: Теперь вопрос изменился на логическое ИЛИ, но я не думаю, что ответ сильно отличается.

0 голосов
/ 03 ноября 2011

Я не могу представить, почему вы хотите сделать это, но вы также можете превратить итерацию в хвостовую рекурсию:

int do_or(int n, int *a, int *b, int *c) { 
    if (0 == n)
       return;

    *c = *a || * b;
    do_or(n-1, a+1, b+1, c+1);
}

Вероятно, лучшей альтернативой было бы закодировать 0 и 1 как фактические биты в беззнаковом числе, и в этом случае вы можете использовать побитовое or для выполнения работы в одной операции:

unsigned long a, b, c;

// code to set/clear bits in a and b elided

c = a | b;

Вам гарантировано, что unsigned long может содержать не менее 32 бит, а unsigned long long может содержать не менее 64.

0 голосов
/ 03 ноября 2011

Если это для x86, то вы можете обрабатывать 16 элементов массива одновременно, используя SSE:

// NB: we're assuming:
//   - N is a multiple of 16
//   - a[], b[], and c[] are 16 byte aligned

for (int i = 0; i < N; i += 16)
{
    __m128i va = _mm_load_si128(&a[i]);
    __m128i vb = _mm_load_si128(&b[i]);
    __m128i vc;
#ifdef LOGICAL_OR // NB: only need these two lines if we are doing logical OR - omit for bitwise OR
    va = _mm_add_epi8(_mm_cmpeq_epi8(va, _mm_set1_epi8(0)), _mm_set1_epi8(1));
    vb = _mm_add_epi8(_mm_cmpeq_epi8(vb, _mm_set1_epi8(0)), _mm_set1_epi8(1));
#endif
    vc = _mm_or_si128(va, vb);
    _mm_store_si128(vc, &c[i]);
}
0 голосов
/ 03 ноября 2011

преждевременная оптимизация. положить это в профилировщик, прежде чем тратить больше времени Компилятор может делать такие вещи, как развернуть цикл или работать с чанками одновременно от вашего имени.

0 голосов
/ 03 ноября 2011

Вы можете типизировать массив символов к наибольшему целому числу, которое поддерживает ваша машина, а затем выполнить операцию ИЛИ с целыми числами, что сэкономит вам несколько циклов инструкций. Обратите внимание, что вам нужно будет выбрать размер массива, кратный размеру целого числа, которое вы используете.

    #define LARGE_INTEGER unsigned long long

    #define ACTUAL_SIZE 10

    #define SIZEOF_LARGE_INT sizeof(LARGE_INTEGER)

    #define N (ACTUAL_SIZE + (SIZEOF_LARGE_INT - (ACTUAL_SIZE % SIZEOF_LARGE_INT)))

char a[N] = {0,1,0,1,0,1,1,1,1,1};
char b[N] = {1,0,1,0,1,0,1,0,1,0};
char c[N];

LARGE_INTEGER *pa, *pb, *pc;

int i;

for(i = 0; i < N; i = i + SIZEOF_LARGE_INT)
{
    pa = (LARGE_INTEGER*) &a[i];
    pb = (LARGE_INTEGER*) &b[i];
    pc = (LARGE_INTEGER*) &c[i];

    *pc = (*pa) | (*pb);
}
0 голосов
/ 03 ноября 2011

Как насчет:

#define c(index)    (a(index) || b(index))

Это дает вам символический c-массив. Просто удалите объявление переменной c.

...