【问题标题】:OpenMP for loop cause wrong resultOpenMP for 循环导致错误结果
【发布时间】:2016-05-13 13:00:06
【问题描述】:

我想通过部分简单代码将循环性能与 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);
}

【问题讨论】:

  • for (int k = 0; k &lt; MP_TEST_NUM; k++) // just for delay 你希望那是一个空循环吗?那么你最后需要一个;
  • @Johnny Mopp 感谢您的通知。但在添加“;”之后对于延迟循环。结果还是不匹配。
  • 我手动计算结果是 49995000 和 sumNoMP = 49992896 sum = 49994736.....
  • 如果你想避免四舍五入,你可以使用 double
  • 考虑使用 Kahan 求和。

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


【解决方案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上加一百次1然后49995000,结果会和你先加1和49995000,然后再加九十九次1时不同:在第二如上所示,后面的每个 +1 都会向下舍入。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • afValueTmp[i] 中的数字都是整数,并且 49995000 不超过浮点类型范围。为什么会有舍入问题,导致结果不同?我发现一旦我对 sum & sumNoMP 使用 double 类型,所有结果都是正确的。
    猜你喜欢
    • 2017-04-26
    • 1970-01-01
    • 2012-01-16
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多