Если вы будете часто вызывать эти методы, самым быстрым способом будет не битовая манипуляция, а, вероятно, справочная таблица. Определите массив длиной 511 для каждой операции. Пример минуса (вычитание)
static unsigned char maxTable[511];
memset(maxTable, 0, 255); // If smaller, emulates cutoff at zero
maxTable[255]=0; // If equal - return zero
for (int i=0; i<256; i++)
maxTable[255+i] = i; // If greater - return the difference
Массив является статическим и инициализируется только один раз. Теперь ваше вычитание можно определить как встроенный метод или с помощью прекомпилятора:
#define MINUS(A,B) maxTable[A-B+255];
Как это работает? Ну, вы хотите предварительно рассчитать все возможные вычитания для беззнаковых символов. Результаты варьируются от -255 до +255, всего 511 различных результатов. Мы определяем массив всех возможных результатов, но поскольку в C мы не можем получить к нему доступ из отрицательных индексов, мы используем +255 (в [A-B+255]). Вы можете удалить это действие, определив указатель на центр массива.
const unsigned char *result = maxTable+255;
#define MINUS(A,B) result[A-B];
используйте его как:
bsub = MINUS(13,15); // i.e 13-15 with zero cutoff as requested
Обратите внимание, что выполнение происходит очень быстро. Только одно вычитание и одно уважение указателя для получения результата. Нет ветвления. Статические массивы очень короткие, поэтому они будут полностью загружены в кеш процессора для дальнейшего ускорения вычислений.
То же самое будет работать для сложения, но с немного другой таблицей (первые 256 элементов будут индексами, а последние 255 элементов будут равны 255, чтобы эмулировать отсечение за пределами 255).
Если вы настаиваете на работе с битами, ответы, в которых используется (a>b), неверны. Это все еще может быть реализовано как ветвление. Используйте метод знаковых битов
// (num1>num2) ? 1 : 0
#define is_int_biggerNotEqual( num1,num2) ((((__int32)((num2)-(num1)))&0x80000000)>>31)
Теперь вы можете использовать его для расчета вычитания и сложения.
Если вы хотите эмулировать функции max(), min() без ветвления, используйте:
inline __int32 MIN_INT(__int32 x, __int32 y){ __int32 d=x-y; return y+(d&(d>>31)); }
inline __int32 MAX_INT(__int32 x, __int32 y){ __int32 d=x-y; return x-(d&(d>>31)); }
В моих примерах выше используются 32-битные целые числа. Вы можете изменить его на 64, хотя я считаю, что 32-битные вычисления выполняются немного быстрее. Вам решать
person
DanielHsH
schedule
02.11.2015
y ^ ((x ^ y) & -(x < y))
дляint
типов оцениваетmin(x, y)
без ветвления. Это может стать частью возможного решения, основанного на том, что у вас есть. - person Bathsheba   schedule 02.11.2015y ^ ((x ^ y) & -(x < y));
этоmin(x,y)
(обычно) без ветки (гдеx < y
может, в зависимости от машины, все еще быть веткой), но в современной архитектуре есть условное перемещение, которое, вероятно, не намного медленнее. - person Pixelchemist   schedule 02.11.2015char
, то, начиная с C++14, это должно быть дополнением до 2. - person Bathsheba   schedule 02.11.2015I just wonder if there are any better ways to do this, i.e. by some hacky bit manipulations?
Если код не находится в очень критической части с точки зрения производительности, хакерские оптимизации в конечном итоге только усложняют чтение. Я предлагаю более конкретный вопрос, например...are there any more efficient ways...
. - person eerorika   schedule 02.11.2015_mm_adds_epi8
выполняет насыщенное добавление 16 байтов в одной инструкции. - person porglezomp   schedule 03.11.2015_mm_subs_epi8
для вычитания. - person Z boson   schedule 03.11.2015