Почему делает скорость этого решателя SOR, зависят от входа?

Связанный с моим другим вопросом, я теперь изменил решатель разреженной матрицы для использования SOR (Последовательная Сверхрелаксация) метод. Код теперь следующие:

void SORSolver::step() {
    float const omega = 1.0f;
    float const
        *b = &d_b(1, 1),
        *w = &d_w(1, 1), *e = &d_e(1, 1), *s = &d_s(1, 1), *n = &d_n(1, 1),
        *xw = &d_x(0, 1), *xe = &d_x(2, 1), *xs = &d_x(1, 0), *xn = &d_x(1, 2);
    float *xc = &d_x(1, 1);
    for (size_t y = 1; y < d_ny - 1; ++y) {
        for (size_t x = 1; x < d_nx - 1; ++x) {
            float diff = *b
                - *xc
                - *e * *xe
                - *s * *xs - *n * *xn
                - *w * *xw;
            *xc += omega * diff;
            ++b;
            ++w; ++e; ++s; ++n;
            ++xw; ++xe; ++xs; ++xn;
            ++xc;
        }
        b += 2;
        w += 2; e += 2; s += 2; n += 2;
        xw += 2; xe += 2; xs += 2; xn += 2;
        xc += 2;
    }
}

Теперь странная вещь: если я увеличиваюсь omega (релаксационный фактор), скорость выполнения начинает зависеть существенно от значений в различных массивах!

Для omega = 1.0f, время выполнения является более или менее постоянным. Для omega = 1.8, в первый раз будет обычно требоваться, скажем, 5 миллисекунд для выполнения этого step() 10 раз, но это будет постепенно увеличиваться почти до 100 мс во время моделирования. Если я установил omega = 1.0001f, Я вижу соответственно небольшое увеличение во время выполнения; выше omega идет, более быстрое время выполнения увеличится во время моделирования.

Так как все это встраивается в жидком решателе, трудно придумать автономный пример. Но я сохранил начальное состояние и повторно выполнил решатель на том состоянии каждый временной интервал, а также решающий для фактического временного интервала. Для начального состояния это было быстро для последующих временных интервалов инкрементно медленнее. Так как все остальное равно, который доказывает, что скорость выполнения этого кода зависит от значений в тех шести массивах.

Это восстанавливаемо на Ubuntu с g ++, а также в 64-разрядном Windows 7 при компиляции для 32 битов с VS2008.

Я слышал, что NaN и значения Inf могут быть медленнее для вычислений с плавающей точкой, но никакой NaNs или Infs не присутствуют. Действительно ли возможно, что скорость вычислений плавающих иначе зависит от значений входных чисел?

6
задан Community 23 May 2017 в 12:11
поделиться

2 ответа

Короткий ответ на ваш последний вопрос "да" - денормализованные (очень близкие к нулю) числа требуют специальной обработки и могут быть намного медленнее. Я предполагаю, что они проникают в симуляцию с течением времени. См. соответствующий пост SO: Время выполнения математики с плавающей запятой

Установка управления плавающей запятой на очистку денормальных чисел до нуля должна решить эту проблему с незначительным влиянием на качество моделирования.

5
ответ дан 17 December 2019 в 04:45
поделиться

Ответ celion'а оказался правильным. В сообщении, на которое он ссылается, говорится о включении функции flush-to-zero денормализованных значений:

#include <float.h>
_controlfp(_MCW_DN, _DN_FLUSH);

Однако, это только для Windows. Используя gcc в Linux, я сделал то же самое с помощью встроенной сборки:

int mxcsr;
__asm__("stmxcsr %0" : "=m"(mxcsr) : :);
mxcsr |= (1 << 15); // set bit 15: flush-to-zero mode
__asm__("ldmxcsr %0" : : "m"(mxcsr) :);

Это моя первая сборка на x86, так что ее, вероятно, можно улучшить. Но для меня это работает.

0
ответ дан 17 December 2019 в 04:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: