(Как я бы сделал исходную задачу поиска первого положительного double значения в массиве/строке)
Я бы векторизовал внутренний цикл поиска на AVX, примерно так (для архитектуры Haswell):
Код:
int FindByFirst0(double * p, int len) {//Цикл поиска первого положительного значения в одной строке массива
double * s = p + len;
while ((p < s) && (p & 0x1F != 0))//Цикл до обнуления младших 5 битов адреса
if (*p++ > 0) return 1;
int n = (s & -32) / 8 / 4;//Проверяем по 4 элемента
// while (n != 0) {
// if (test32(p)) break;//Проверка сразу 4-х элементов
// p += 4;//Проверяем по 4 элемента
// --n;
// }
asm {
mov ESI,p
mov ECX,n
jecxz .find
vpxor ymm0,ymm0,ymm0
.scan:
vcmppd ymm1,ymm0,[ESI],1
vptest ymm1,ymm1
jnz .find
add ESI,32
dec ECX
jnz .scan
.find:
mov p,ESI
}
//Сюда попадает если в 4-х элементах начиная с p найдено условие останова или дошли [почти] до конца массива
while (p < s)
if (*p++ > 0) return 1;
return 0;
}
//Использование:
for (ii = 0; ii < nCol; ii++)
if (*(fe + ii) == 0)
nAlt += FindByFirst0(aPos[ii], NStr);
Весь цикл scan выполняется 1.5 такта на 4 элемента до момента нахождения условия останова. При этом все 4 вычислительных конвейера (0,1,5,6) заняты на 100% (и потому Hyper-threading полностью в пролёте). А конвейеры чтения памяти заняты на 33%.
Итоговая скорость примерно 10млрд чисел в секунду на ядро, при том что DDR3-1600 память в двухканальном режиме выдаёт лишь 3млрд чисел в секунду (DDR4-2400 выдаёт меньше 5млрд) и будет тормозом.
С single числами скорость была бы ровно вдвое выше.
При развороте цикла вчетверо с объединением результатов тремя командами vpor и одной vptest и одним условным переходом получим предельно возможную скорость 0.25 такта на число, меньше не может быть из-за 100% загрузки 1-го конвейера командой vcmppd (потому и HT данной программе не поможет). Зато остальные конвейеры загружены на 62% (0 и 5) и 75% (6) и 50% (чтение памяти).
Но память даже двухканальная DDR4-2400 столько чисел выдать не успеет и будет тормозом.