为什么这个SOR求解器的速度取决于输入?

时间:2010-03-06 15:15:35

标签: c++ optimization floating-point sparse-matrix

与我的other question相关,我现在修改了稀疏矩阵求解器以使用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,第一次,执行此step() 10次通常需要5毫秒,但在模拟期间这将逐渐增加到近100毫秒。如果我设置omega = 1.0001f,我会看到执行时间略有增加; omega越高,模拟过程中执行时间就越快。

由于所有这些都嵌入在流体求解器中,因此很难找到一个独立的例子。但是我保存了初始状态,并在每个步骤重新运行该状态的求解器,以及求解实际时间步长。对于初始状态,它很快,随后的时间步长逐渐变慢。由于其他条件相同,这证明了此代码的执行速度取决于这六个数组中的值。

使用g ++在Ubuntu上以及在使用VS2008编译32位时在64位Windows 7上可以重现。

我听说浮点计算的NaN和Inf值可能较慢,但不存在NaN或Infs。浮动计算的速度是否有可能取决于输入数字的值?

2 个答案:

答案 0 :(得分:5)

对上一个问题的简短回答是“是” - 非规范化(非常接近于零)数字需要特殊处理,而且速度要慢得多。我的猜测是,随着时间的推移,他们正在进入模拟。请参阅此相关的SO帖子:Floating Point Math Execution Time

设置浮点控制以将非正规数刷新为零应该处理模拟质量上可忽略不计的事物。

答案 1 :(得分:0)

celion's answer原来是正确的。他链接的帖子说要打开非规范化值的齐射为零:

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

但是,这只是Windows。在Linux上使用gcc,我用内联汇编的方式做了同样的事情:

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

这是我有史以来的第一个x86程序集,所以它可能会得到改进。但这对我有用。