#include <iostream>
#include <iomanip>
#include <cstdlib>
#define N 10000000
inline double frand() { return rand() / (double)RAND_MAX; }
double blockSum(double *arr, int n, int n_block) {
double *sum_block = new double[n_block];
double sum = 0.0;
for (int i=0; i<n_block; i++) {
sum_block[i] = 0.0;
for (int j=0; j<n/n_block; j++) {
sum_block[i] += arr[n/n_block * i + j];
}
}
for (int i=0; i<n_block; i++) {
sum += sum_block[i];
}
delete [] sum_block;
return sum;
}
int main() {
double *darr = new double[N];
srand(1973);
for (int i=0; i<N; i++) {
darr[i] = frand();
}
double sum_tot = 0.0;
for (int i=0; i<N; i++) {
sum_tot += darr[i];
}
std::cout << "sum_tot " << std::fixed << std::setprecision(10) << sum_tot << std::endl;
double sum_block_tot;
sum_block_tot = blockSum(darr, N, 1);
std::cout << "sum_block_tot (1) " << std::fixed << std::setprecision(10) << sum_block_tot << std::endl;
sum_block_tot = blockSum(darr, N, 10);
std::cout << "sum_block_tot (10) " << std::fixed << std::setprecision(10) << sum_block_tot << std::endl;
sum_block_tot = blockSum(darr, N, 100);
std::cout << "sum_block_tot (100) " << std::fixed << std::setprecision(10) << sum_block_tot << std::endl;
sum_block_tot = blockSum(darr, N, 1000);
std::cout << "sum_block_tot (1000) " << std::fixed << std::setprecision(10) << sum_block_tot << std::endl;
delete [] darr;
return 0;
sum_tot 4998539.4213524628
sum_block_tot (1) 4998539.4213524628
sum_block_tot (10) 4998539.4213524340
sum_block_tot (100) 4998539.4213524330
sum_block_tot (1000) 4998539.4213524330
在上面的例子中,darr
的总和得到不同的值,这取决于我们如何分块初始数组并在部分块求和后得到总和。
我不是在问为什么会发生这种情况--显然这应该与浮点数有关。我想知道是否有任何明确的解决方案来减轻(甚至消除)这种依赖性。
特别是在涉及并行化的计算中,有很多情况需要将原始数据划分为块,进行一些计算,并对主线程进行简化。如果计算值根据硬件结构而不时地不同,则不是那么好。
如果一个人正在进行粒子模拟,其中有数十亿个粒子,但结果会根据块的大小或求和的顺序而不同呢?
关于这一点有一些评论,以减少数字的丢失,但大多数都不适用于HPC应用程序-我们只是不能按大小对值进行排序,并决定每次求和的顺序。
在并行计算环境中,有没有什么好的方法来做“好的求和”?
PS)我想确认sum_block_tot (1)
是最接近真实的和的值,块的大小越大,结果通常会降级。
1条答案
按热度按时间vnjpjtjt1#
如果不能对值进行排序,就无法提高准确性。a + B + c + d!=(a + B)+(c + d)在浮点数学中。
您可以使用块的
std::heap
,而不是整个范围的std::sort
。它可以增加每个块的精度和块的和的精度。