浮点数运算:加法顺序为何会影响计算结果?
浮点数加法顺序为啥会影响结果?你的C代码没问题!
兄弟,别怀疑你的代码——这真不是你写的C代码有问题,纯纯是浮点数天生的精度局限性导致的!虽然在数学里加法交换律绝对成立,但计算机里的浮点数加法可不吃这一套。
为啥顺序会影响结果?
浮点数(比如C里的float和double)是用有限位数的二进制来近似表示实数的,这意味着它们的精度是有限的。当你把不同量级的数相加时,小的数很可能会被大的数“吞噬”:
比如你有一个很大的数1e18(double类型),再加上1——因为1e18的二进制表示里,最低有效位的量级已经远大于1了,加完之后结果还是1e18,相当于1直接“消失”了。
回到你的场景:随机数向量里有大有小,原来的随机顺序可能是大小数穿插相加,而排序后(比如从小到大或从大到小),相加的过程中精度损失的方式完全不同:
- 如果先加一堆小数,它们的和会慢慢累积到一个足够大的量级,再和大数相加时就不容易被吞噬;
- 如果先加大数,后面的小数加进去时可能直接被覆盖,导致最终的和和随机顺序的结果不一样。
怎么减少这种误差?
给你两个实用的解决方案:
- Kahan求和算法:这是一种专门用来减少浮点数求和误差的技巧,它会记录每次相加时丢失的误差,在下一次运算时把误差补回来,能大幅提升求和的精度。C语言里的实现大概是这样的:
double kahan_sum(double arr[], int n) { double sum = 0.0; double error = 0.0; for (int i = 0; i < n; i++) { double temp = arr[i] - error; double new_sum = sum + temp; error = (new_sum - sum) - temp; sum = new_sum; } return sum; }
- 排序后从小到大相加:把所有数按从小到大排序后再相加,能让小数先累积到足够大的量级,再和大数相加,减少被吞噬的概率,比随机顺序的求和精度更高。
最后再提醒一句:永远不要直接用==比较两个浮点数是否相等,应该用一个很小的阈值(比如1e-9)来判断两个数的差是否小于这个阈值,像这样:
if (fabs(sum1 - sum2) < 1e-9) { // 认为两个和相等 }
内容的提问来源于stack exchange,提问作者GnomeSort
相关产品推荐
相关产品推荐

