c++ - 计算数组c ++的平均值
问题描述
当我尝试以两种方式计算数组的平均值时遇到了一个问题。下面是代码:
float sum1, sum2, tmp, mean1, mean2;
double sum1_double, sum2_double, tmp_double;
int i, j;
int Nt=29040000; //array size
int piecesize=32;
int Npiece=Nt/piecesize;
float* img;
float* d_img;
double* img_double;
img_double = (double*)calloc(Nt, sizeof(double));
cudaHostAlloc((void**)&img, sizeof(float)*Nt, cudaHostAllocDefault);
cudaMalloc((void**)&d_img, sizeof(float)*Nt);
...
//Some calculation is done in GPU and the results are stored in d_img;
...
cudaMemcpy(img, d_img, Nt*sizeof(float), cudaMemcpyDeviceToHost);
for (i=0;i<Nt;i++) img_double[i]=(double)img[i];
//Method 1
sum1=0;
for (i=0;i<Nt;i++)
{ sum1 += img[i]; }
sum1_double=0;
for (i=0;i<Nt;i++)
{ sum1_double += img_double[i]; }
//Method 2
sum2=0;
for (i=0;i<Npiece;i++)
{ tmp=0;
for (j=0;j<piecesize;j++)
{ tmp += img[i*piecesize+j];}
sum2 += tmp;
}
sum2_double=0;
for (i=0;i<Npiece;i++)
{ tmp_double=0;
for (j=0;j<piecesize;j++)
{ tmp_double += img_double[i*piecesize+j];}
sum2_double += tmp_double;
}
mean1=sum1/(float)Nt;
mean2=sum2/(float)Nt;
mean1_double=sum1_double/(double)Nt;
mean2_double=sum2_double/(double)Nt;
cout<<setprecision(15)<<mean1<<endl;
cout<<setprecision(15)<<mean2<<endl;
cout<<setprecision(15)<<mean1_double<<endl;
cout<<setprecision(15)<<mean2_double<<endl;
输出:
132.221862792969 129.565872192383 129.565938340543 129.565938340543
两种方法得到的结果,mean1=129.6,mean2=132.2,有显着差异。我可以知道为什么吗?
提前非常感谢!
解决方案
原因是浮点运算不精确。当您累积整数时,当 abs(value) 大于 2 24时,浮点数变得不精确(我在这里假设 IEEE-754 32 位)。例如,float 无法精确存储 16777217(它将变为 16777216 或 16777218,具体取决于舍入模式)。
假设您的第二次计算是更精确的计算,因为由于单独的tmp
累积而损失的精度更少。
sum1
将您的, sum2
,tmp
变量更改为long long int
, 希望您在两次计算中都能得到相同的结果。
注意:我假设您img
存储整数数据。如果它存储浮点数,那么就没有简单的方法可以完美地解决这个问题。一种方法是使用而double
不是float
forsum1
和。差异会存在,但会小得多。还有一些技术可以比简单的求和更精确地累加 s。像卡汉求和。sum2
tmp
float
推荐阅读
- python - 我们可以独立管理单个 Django 项目中每个 django 应用程序的部署吗?
- r - 奇怪的错误我无法在 R 中解决随机森林
- javascript - 页面刷新时保存并添加回存储值
- java - 我如何在主要活动中使用结果
- r - if 参数中的“参数长度为零”错误 - 比较向量中的两个值
- google-maps - 谷歌地图距离矩阵单位未正确显示
- c# - System.FormatException: '反序列化属性时发生错误。在 mongoDB.Driver C# 的帮助下使用聚合函数
- sql - 使用生成的系列填充列
- python - 涉及 Enum 的多重继承元类冲突
- heroku-postgres - 连接尝试失败。尝试连接到 Heroku PostgreSQL 时