OpenMP for循环导致错误的结果

时间:2016-05-13 13:00:07

标签: visual-c++ floating-point openmp reduction

我想通过部分简单代码将循环性能与openmp进行比较。但结果是错误的。

我已经使用减少以避免竞争条件,但从不工作。

这是我的代码:感谢任何建议

void TestMP_1(){
    float afValueTmp[MP_TEST_NUM] = { 0 }; // MP_TEST_NUM = 10000
    float sum = 0, sumNoMP = 0;
    float fDiff = 0;
    double eTDiff = 0;
    double t0 = 0;
    double t1 = 0;

    for (int i = 0; i < MP_TEST_NUM; i++)
    {
        afValueTmp[i] = i;
    }

    t0 = (double)getTickCount();
    for (int i = 0; i < MP_TEST_NUM; i++)
    {
        for (int k = 0; k < MP_TEST_NUM; k++);  // just for delay

        sumNoMP += afValueTmp[i];   // equation 4
    }

    t0 = ((double)getTickCount() - t0) / getTickFrequency();
    t1 = (double)getTickCount();

    #pragma omp parallel for reduction( +:sum)
    for (int i = 0; i < MP_TEST_NUM; i++)
    {
        for (int k = 0; k < MP_TEST_NUM; k++);  // just for delay

        sum += afValueTmp[i];
    }

    t1 = ((double)getTickCount() - t1) / getTickFrequency();
    eTDiff = t0 - t1;   // time improve
    fDiff = sum - sumNoMP;  // check result
    printf("%.3f\n", eTDiff);
}

2 个答案:

答案 0 :(得分:1)

您正面临浮点准确性问题。请允许我详细说明:

#include <stdio.h>

int main(void)
{
    float myOrigNumber = 49995000;
    float myNumber = myOrigNumber + 1.;

    printf ("orig: %f new: %f diff: %f\n",
            myOrigNumber, myNumber, myNumber-myOrigNumber);
    return 0;
}

结果将是:

orig: 49995000.000000 new: 49995000.000000 diff: 0.000000

那么,+1去哪儿了?

float类型只有7到8位有效数字。它们在哪里并不重要,因为浮点数在内部始终以Scientific notation表示为x.xxE + yy表示法,其中x.xx有24位,yy有8位。 数字49995001大于2 ^ 24(16,777,216),因此它将四舍五入到可以准确表示的最接近的数字,显然是49995000。

这就是为double使用sum可以减轻您的痛苦的原因。但这不是一个真正的解决方案。减少操作要求操作必须可交换。 但是对于浮点加法不一定是这种情况:如果你向sum添加100次1然后49995000,结果将与你第一次添加1和49995000,然后是99次1:in时不同第二种情况,后面的每一个+1都会向上舍入,如上所示。

答案 1 :(得分:0)

根据您所写的内容和预期的舍入结果,您的结果可能是正确的。