OpenMP中的奇怪浮动行为

时间:2011-01-20 16:07:26

标签: c debugging floating-point openmp

我正在运行以下OpenMP代码

        #pragma omp parallel shared(S2,nthreads,chunk) private(a,b,tid)
    {
        tid = omp_get_thread_num();
        if (tid == 0)
        {
            nthreads = omp_get_num_threads();
            printf("\nNumber of threads = %d\n", nthreads);
        }
        #pragma omp for schedule(dynamic,chunk) reduction(+:S2)
        for(a=0;a<NREC;a++){
            for(b=0;b<NLIG;b++){
                S2=S2+cos(1+sin(atan(sin(sqrt(a*2+b*5)+cos(a)+sqrt(b)))));
            }
        } // end for a
    } /* end of parallel section */

对于NREC = NLIG = 1024和更高的值,在8核心板中,我获得了7次加速。问题是如果我比较变量S2的最终结果,它与串行版本中获得的确切结果相差1到5%。可能是什么原因?我应该使用一些特定的编译选项来避免这种奇怪的浮动行为吗?

2 个答案:

答案 0 :(得分:2)

浮点数的加/减顺序会影响精度。

举一个简单的例子,假设您的机器存储了2位小数,并且您计算的值是1 + 0.04 + 0.04。

  • 如果先进行左侧加法,则得到1.04,将其舍入为1.第二次加法将再次给出1,因此最终结果为1.

  • 如果你先做正确的加法,你得到0.08。添加到1,这将给出1.08,其舍入为1.1。

为获得最高精度,最好添加从小到大的值。

另一个原因可能是CPU上的浮点寄存器可能包含的位数多于主存储器中的浮点数。因此,如果某个中间结果缓存在寄存器中,则更准确,但如果它被换出到内存则会被截断。

另见this question in the C++ FAQ

答案 1 :(得分:0)

众所周知,当减去两个大值(或者添加两个具有不同符号的大值)时,机器浮点运算是有缺陷的,因此产生小的差异。因此,对振荡符号序列求和可能在每次迭代时引入严重错误。另一个有缺陷的案例是两个操作数的大小差别很大 - 较小的操作数实际上取消了它们 分离正负操作数并分别对每个组进行求和,然后加上(减去)组结果可能很有用。
如果准确性至关重要,则可能需要对每个组进行预先排序,并在每个组内执行两次求和。第一个总和将从中心向最大(头部),第二个将从最小(尾部)朝向中心。结果组总和将是部分运行的总和。