c++ 根据块大小获取不同的求和值

wyyhbhjk  于 2023-05-20  发布在  其他
关注(0)|答案(1)|浏览(95)
#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)是最接近真实的和的值,块的大小越大,结果通常会降级。

vnjpjtjt

vnjpjtjt1#

如果不能对值进行排序,就无法提高准确性。a + B + c + d!=(a + B)+(c + d)在浮点数学中。
您可以使用块的std::heap,而不是整个范围的std::sort。它可以增加每个块的精度和块的和的精度。

相关问题