我已经并行化了一个简单的代码,用于在数值上计算函数的积分。我使用函数y=2*sqrt(1-x^2)
从-1到1.这个积分等于Pi。
算法是计算积分的最简单方法,我猜大家都是在学校里学到的。我"画"功能下的小尺寸矩形并计算它们的面积。
顺序算法是:
double calc_integral_seq(int left_bound, int right_bound){
int i;
double x, sum=0.0;
double step = 1.0/ (double) STEPS;
for(i=left_bound*STEPS; i<right_bound*STEPS; i++){
x = (i+0.5)*step;
sum += f(x);
}
return sum*step;
}
现在,当我并行化此代码时(例如,仅使用for-loop构造#pragma omp parallel for private(x) reduction(+:sum)
),对于大量STEPS
,算法会更快。
但它也更准确!怎么可能?这是一个确定性的算法,它应该计算完全相同的值或者我错了吗?怎么解释这个?
答案 0 :(得分:2)
这是一个四舍五入的问题。每当您将非常小的数字添加到非常大的数字时,就会出现舍入误差,因为具有大指数的浮点数无法准确描述小的变化。每次添加的舍入误差随着sum
值的增加而增加。
通过并行计算,本地sum
不会像串行循环一样大。因此在本地,舍入误差较小。对于全局sum
的总和,本地结果更加接近,因此舍入较少。
避免浮点舍入错误的常规算法是Kahan summation或pairwise summation。