Я использую компактную структуру из 2 беззнаковых шорт, указывающих начальную и конечную позицию.
Я должен быть в состоянии быстро определить, есть ли Range
объекты с длиной (от начала до конца) после порогового значения.
Я собираюсь иметь огромное количество объектов, каждый со своим Range
массив, поэтому невозможно отследить, какой Range
объекты находятся выше порога в списке или что-то. Этот код также будет запускаться очень часто (много раз в секунду для каждого массива), поэтому он должен быть эффективным.
struct Range
{
unsigned short start;
unsigned short end;
}
Я всегда буду иметь массив Range
размером 2 ^ н. Хотя я хотел бы прервать работу, как только что-то превысит порог, я почти уверен, что будет проще просто ИЛИ все это вместе и проверить в конце … при условии, что я могу векторизовать цикл. Хотя, если бы я мог сделать оператор if для части результатов для каждого вектора, это было бы здорово.
size_t rangecount = 1 << resolution;
Range* ranges = new Range[rangecount];
...
bool result = false;
for (size_t i = 0; i < ranges; ++i)
{
result |= (range[i].end - range[i].start) > 4;
}
Неудивительно, что авто-векторизатор выдает ошибку 1202, потому что мой тип данных не 32 или 64-битный. Я действительно не хочу удваивать свой размер данных и делать каждое поле целым без знака. Так что я предполагаю, что для этого не подходит подход с векторизацией.
Существуют ли векторные инструкции, которые могут обрабатывать 16-битные переменные? Если есть, как я могу использовать их в C ++ для векторизации моего цикла?
Вам интересно, если какое-либо значение больше 4?
Да, для этого есть инструкции SIMD. К сожалению, авто-векторизация не в состоянии справиться с этим сценарием. Вот векторизованный алгоритм:
diff_v = end_v - start_v; // _mm_hsub_epi16
floor_v = max(4_v, diff_v); // _mm_max_epi16
if (floor_v != 4_v) return true; // wide scalar comparison
использование _mm_sub_epi16
со структурой массивов или _mm_hsub_epi16
с массивом структур.
На самом деле с start
хранится первым в памяти, вы будете работать над start_v - end_v
так что пользуйтесь _mm_min_epi16
и вектор -4
,
Каждая инструкция SSE3 будет выполнять 8 сравнений одновременно. Быстрее будет возвращаться раньше, чем зацикливаться. Однако, разворачивая цикл немного больше, вы приобретете дополнительную скорость (передайте первый набор результатов в упакованную функцию min / max, чтобы объединить их).
Таким образом, вы в конечном итоге (примерно):
most_negative = threshold = _mm_set_epi64(0xFCFCFCFCFCFCFCFC); // vectorized -4
loop:
a = load from range;
b = load from range;
diff = _mm_hsub_epi16(a, b);
most_negative = _mm_min_epi16(most_negative, diff);
// unroll by repeating the above four instructions 4 times or so
if (most_negative != threshold) return true;
repeat loop
Других решений пока нет …