如何让GNU GCC同样优化OpenMP线程

3
这是我的第一篇帖子。耶!回到问题:
我正在学习如何使用OpenMP。我的IDE是Code::Blocks。我想改进一些旧程序。我需要确保结果完全相同。似乎在主线程中,“for”循环的优化与其他线程不同。
例如:
#include <iostream>
#include <omp.h>
int main()
{
    std::cout.precision(17);
    #pragma omp parallel for schedule(static, 1) ordered
    for(int i=0; i<4; i++)
    {
        double sum = 0.;
        for(int j=0; j<10; j++)
        {
            sum += 10.1;
        }
        #pragma omp ordered
        std::cout << "thread " << omp_get_thread_num() <<  " says " << sum << "\n";
    }
    return 0;
}

生产
thread 0 says 101
thread 1 says 100.99999999999998579
thread 2 says 100.99999999999998579
thread 3 says 100.99999999999998579

我该如何确保所有线程都能够获得与我的单线程程序(未使用OpenMP)相同的优化呢?
编辑:
编译器是“TDM-GCC编译器和GDB调试器(版本4.9.2,32位,SJLJ)”,不知道这是什么意思。这是IDE的“默认设置”。我对编译器的区别不熟悉。
所提供的输出来自“Release”构建,其中添加了“-O2”参数。
“-O”、“-O1”和“-O3”参数中没有一个能够产生“101”。
您可以尝试从Dropbox(zip文件,也包含可能需要的dll文件)下载我的.exe文件。

1
你能提供更多信息吗?你使用的是哪个编译器?例如,如果我使用gcc 4.8.x,我会得到:所有线程的线程X都说100.99999999999999。话虽如此,大多数OpenMP运行时只是为循环体创建一个新的轮廓例程,每个线程执行相同的例程。 - Harald
同样适用于gcc 4.9和5.3版本。 - Gilles
@Gilles 是同一个IDE吗?因为Code::Blocks在构建过程中会添加额外的参数,比如“-O2”。 - Stratubas
我尝试了32位和64位模式下使用gcc 4.9.3和gcc 5.3.0,采用不同级别的优化:我总是得到所有线程打印相同的输出,大多数情况下是“100.99999999999999”。只有在32位模式下并且有-O2选项时,我才会得到“101”,但对于所有线程都是如此,因此即使在这里也没有差异... - Gilles
@Gilles 我只在线程0中使用-O2得到了101。这可能是硬件问题吗?这可能是OpenMP版本的问题(我不知道我正在使用哪个版本...)? - Stratubas
显示剩余2条评论
2个回答

2

这是因为float或double数据类型无法表示像20.2这样的某些数字。

#include <iostream>
int main()
{
    std::cout.precision(17);
    double a=20.2;
    std::cout << a << std::endl;
    return 0;
}

它的输出结果将会是:

20.199999999999999

想要了解更多信息,请参阅当两个浮点数相加时出现意外输出

不知道为什么第一个线程没有发生这种情况,但是如果你删除openMP,你仍然会得到相同的结果。


1
问题在于为什么应该执行完全相同的线程会得到不同的结果,而不是有理数可能不符合预期的原因。 - Voo
@Voo 是正确的。我知道我不会得到 20.2,但如果我将其乘以10,我需要得到201.999999999999997 或 202,在单线程程序中能够保持一致。 - Stratubas

0

从我的理解来看,这只是数字精度的问题。对于双精度值类型,您应该期望16位数字精度。

也就是说,结果为101 +/- 1.e-16*101

这正是您可以得到的范围。除非您使用四倍精度之类的东西,否则这就是最好的了。


1
问题在于为什么应该执行完全相同的线程会得到不同的结果,而不是有理数可能不符合预期的原因。 - Voo
我想改进一些旧程序。我需要确保[b]结果完全相同[/b]。在可达到的精度范围内,结果是相同的。除非您使用一些四倍精度数据类型,否则这将不会得到改善。即使您这样做,您仍将面临完全相同的问题,只是位移了16个数字。 - Mohammed Li
@Voo 是正确的。在我的程序中,最后几位数字很重要,因为存在“蝴蝶效应”链接 - Stratubas
@Stratubas:“在我的程序中,最后几位数字很重要。”嗯,如果您使用任何物理测量作为输入,则显然不可能。米的长度未知到那个精度,其他基本单位也存在类似的问题! - Jim Cownie
1
@Jim 当然可以...但是我没有使用物理测量 :-) - Stratubas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接