// 开启omp并行, float计算误差累积到了0.2.
{
std::cout.precision(14);
std::array<float, 100000> da;
for (size_t i = 0; i < da.size(); i++)
da[i] = 1.0f * i / da.size();
long cnt = 0;
float cf = 0;
double cdb = 0;
#pragma omp parallel for
for (int i = 0; i < 100000; i++)
{
#pragma omp critical
{
cnt++;
cf += da[i];
cdb += da[i];
}
}
// x86 debug 输出: 100000 49999.6953125 49999.5 (49999.6953125这个值, 还每次都不一样)
// x86 release 输出: 100000 49999.54296875 49999.5 (49999.54296875这个值, 还每次同样不一样)
std::cout << cnt << " " << cf << " " << cdb << std::endl;
cnt = 0;
cf = 0;
cdb = 0;
for (int i = 0; i < 100000; i++)
{
cnt++;
cf += da[i];
cdb += da[i];
}
// x86 debug 输出: 100000 49999.51171875 49999.5
// x86 release 输出: 100000 49999.51171875 49999.5
std::cout << cnt << " " << cf << " " << cdb << std::endl;
}
float误差打球,你用用精度更高的double
不知道你这个问题是否已经解决, 如果还没有解决的话:这个问题的根本原因是由于并行计算过程中的竞态条件,导致计算结果产生了误差。要解决这个问题,可以采取以下几个步骤:
将浮点计算量尽量减少:在示例代码中,浮点计算的位置都被#pragma omp critical
所保护,这导致了所有的浮点计算都是串行执行的,无法充分利用并行性能。所以,首先要将浮点计算的粒度调整到最小,避免将不必要的计算放在临界区内。可以将#pragma omp critical
注释掉,使得所有线程都可以并行执行计算。
采用精度更高的数据类型:示例代码中使用的是float
类型进行计算,这个数据类型的精度有限,容易产生误差。可以尝试将float
改为double
,或者使用更高精度的库来进行浮点计算,如boost的multiprecision
库。
采用更合理的算法:有时候,误差的产生也与算法的选择有关。可以探索更加稳定的数值计算算法,避免误差的累积。可以参考数值计算的经典算法,如Kahan summation算法等。
修改后的示例代码如下所示:
{
std::cout.precision(14);
std::array<float, 100000> da;
for (size_t i = 0; i < da.size(); i++)
da[i] = 1.0f * i / da.size();
long cnt = 0;
double cf = 0;
double cdb = 0;
#pragma omp parallel for
for (int i = 0; i < 100000; i++)
{
cnt++;
// 注意:不要在这里做多余的浮点计算
cf += da[i];
cdb += da[i];
}
// x86 debug 输出: 100000 49999.6953125 49999.5 (49999.6953125这个值, 还每次都不一样)
// x86 release 输出: 100000 49999.54296875 49999.5 (49999.54296875这个值, 还每次同样不一样)
std::cout << cnt << " " << cf << " " << cdb << std::endl;
cnt = 0;
cf = 0;
cdb = 0;
for (int i = 0; i < 100000; i++)
{
cnt++;
cf += da[i];
cdb += da[i];
}
// x86 debug 输出: 100000 49999.51171875 49999.5
// x86 release 输出: 100000 49999.51171875 49999.5
std::cout << cnt << " " << cf << " " << cdb << std::endl;
}
希望以上解决方案能够解决您所遇到的问题,如果还有其他疑问,请随时提出。