Для small L вы можете использовать оператор switch вместо цикла. Например, если L = 8, вы можете иметь:
int dot8(unsigned int X, const int Y[])
{
switch (X)
{
case 0: return 0;
case 1: return Y[0];
case 2: return Y[1];
case 3: return Y[0]+Y[1];
// ...
case 255: return Y[0]+Y[1]+Y[2]+Y[3]+Y[4]+Y[5]+Y[6]+Y[7];
}
assert(0 && "X too big");
}
И если L = 32, вы можете написать функцию dot32 (), которая вызывает dot8 () четыре раз, если возможно, встроенная. (Если ваш компилятор отказывается встроить dot8 (), вы можете переписать dot8 () как макрос для принудительного встраивания.) Добавлено :
int dot32(unsigned int X, const int Y[])
{
return dot8(X >> 0 & 255, Y + 0) +
dot8(X >> 8 & 255, Y + 8) +
dot8(X >> 16 & 255, Y + 16) +
dot8(X >> 24 & 255, Y + 24);
}
Это решение, как указывает Микера, может иметь стоимость кэша команд; в этом случае может помочь использование функции dot4 ().
Дальнейшее обновление : это можно комбинировать с решением Микеры:
static int dot4(unsigned int X, const int Y[])
{
switch (X)
{
case 0: return 0;
case 1: return Y[0];
case 2: return Y[1];
case 3: return Y[0]+Y[1];
//...
case 15: return Y[0]+Y[1]+Y[2]+Y[3];
}
}
Глядя на полученный ассемблерный код с опциями -S -O3 с gcc 4.3.4 на CYGWIN, я немного удивлен, увидев, что это автоматически встроено в dot32 (), с восемь таблицы переходов по 16 записей.
Но добавление __attribute __ ((__ noinline__)), кажется, производит более привлекательный ассемблер.
Другим вариантом является использование сквозных операторов в операторе switch, но gcc добавляет инструкции jmp и выглядит не так быстро.
Редактировать - Совершенно новый ответ: После размышления о 100-процентном штрафе, упомянутом Антсом Аасмой, и другими ответами, вышеупомянутое, вероятно, не оптимально. Вместо этого вы можете вручную развернуть цикл как в:
int dot(unsigned int X, const int Y[])
{
return (Y[0] & -!!(X & 1<<0)) +
(Y[1] & -!!(X & 1<<1)) +
(Y[2] & -!!(X & 1<<2)) +
(Y[3] & -!!(X & 1<<3)) +
//...
(Y[31] & -!!(X & 1<<31));
}
Это, на моей машине, генерирует 32 x 5 = 160 быстрых инструкций. Умный компилятор мог предположительно развернуть другие предложенные ответы, чтобы дать тот же результат.
Но я все еще проверяю дважды.