gpt4 book ai didi

c++ - 如何求和大量的 float ?

转载 作者:可可西里 更新时间:2023-11-01 15:31:54 28 4
gpt4 key购买 nike

我构建了一个并行求和代码来对大量 float 求和,然后我发现当数字的数量大于 100000000 时,结果会出错。然后我建立一个串行代码来比较。序列号也得到错误的数字。有人知道为什么吗?谢谢!

我的简单代码如下。

结果是“1.67772e+007”。应该是1e+008

int main()
{
size_t N=100000000;
cout<<"n is : "<<N<<endl;
clock_t start = clock();
task_scheduler_init init;
vector<float> myvec;
vector<float>* pvec;
for(int i=0;i<N;i++)
myvec.push_back(1.0f);
pvec=&myvec;
float mysum;
mysum=parallelSum(pvec);
cout<<" the p sum is: "<<mysum<<endl;
clock_t finish = clock();
cout<<"Time Used = "<<(finish - start)/CLOCKS_PER_SEC<<endl;
mysum=0;
for(int i=0;i<N;i++)
mysum+=myvec[i];
cout<<" the s sum is: "<<mysum<<endl;
return 0;
}

最佳答案

您的问题是由于 float 的可用精度有限。

同时

1.0f + 1.0f == 2.0f, 

你会发现

16777216.0f + 1.0f == 16777216.0f

因为 16777217 不能用 float 格式表示,所以多余的 1.0f 被丢弃了。

看看您的结果 – 1.67772e+007 – 很明显,这正是发生的事情。

您的预期结果 100000000.0 比 16777216.0f 大很多 (6 倍),但是一旦总和达到 16777216.0f 的总和,它就会停留在那里以进行剩余的 8327884 次加法 1.0f。

解决方案:尝试使用 double 而不是 float,它会在遇到此问题之前达到 9007199254740992.0

为什么?

在单精度浮点中,只有 24 位精度可用,2^24 是 16777216。无法将 16777217 编码为 24 位,因此它只是停留在 16777216,因为它是 足够接近真正的答案。当您将许多非常小的数字加到一个大数字上时,真正的问题就出现了,其中小数字的总和相对于大数字来说很重要,但单独来看却不是。

Note that 16777216.0f is not the largest number that can be represented in float, but just represents the limit of precision. For example, 16777216.0f x 2^4 + 2^4 => 16777216.0f x 2^4

double 具有 53 位精度,因此在添加 1.0d 之前最多可以编码 2^53 或 9007199254740992.0失败。


这个问题还代表了并行化浮点运算的另一个危险 - 浮点加法不是关联的,换句话说,你的顺序算法:

Sum(A) = (...((((A1 + A2) + A3) + A4) ... A10000)

可能会产生与并行化版本不同的结果:

Sum(A) = (...((((A1 + A2) + A3) + A4) ... A1000)
+ (...((((A1001 + A1002) + A1003) + A1004) ... A2000)
+ (...((((A2001 + A2002) + A2003) + A2004) ... A3000)
...
+ (...((((A9001 + A9002) + A9003) + A9004) ... A10000)

因为任何给定的步骤都可能在不同程度上失去精度。

这并不意味着哪个更正确,而是您可能会得到意想不到的结果。


如果您真的必须使用float,请尝试以下操作:

  • 将你的数字从最负的到最正的排序(顺序 (N log N))
  • 依次添加每一对:B1 := A1 + A2, B2 := A3 + A4, B3 := A5 + A6这会产生一个新列表 B,其长度是初始列表的一半
  • 在 B 上重复此过程得到 C,C 得到 D,等等
  • 当只剩下一个数字时停止。

请注意,这会将您的算法复杂度从 O(N) 操作更改为 O(N log N) 操作,但产生正确数字的可能性更大。这是相当可并行化的。如果您很聪明,您也许可以合并排序和求和操作。

关于c++ - 如何求和大量的 float ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2148149/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com