double类型求和结果不一致:原因分析及解决方案
两种double求和结果差异的原因及解决办法
问题现象
用两种方式对5个double类型数字求和,得到了略有差异的结果:
- LINQ
Sum()方式结果:127.9325 - 手动逆序累加方式结果:
127.93250000000002
方式一代码
int startIndex = i - (Lenght - 1); Debug.WriteLine("By LINQ:"); Debug.WriteLine(company_data.Close[startIndex]); for (int j = 1; j < Lenght; j++) { Debug.WriteLine(company_data.Close[startIndex + j]); } double sum = deviations.GetRange(startIndex, Lenght).Sum(); Debug.WriteLine("\nSUM = " + sum);
方式一输出
By LINQ: 25.51 25.585 25.68 25.5975 25.56 SUM = 127.9325
方式二代码
double sum = 0.0; Debug.WriteLine("By Method:"); for (int i = index; i > index - lenght; i--) { Debug.WriteLine(source[i]); Debug.WriteLine("sum before = " + sum); sum += deviations[i]; Debug.WriteLine("sum after = " + sum); } Debug.WriteLine("sum = " + sum);
方式二输出
By Method: 25.56 sum before = 0 sum after = 25.56 25.5975 sum before = 25.56 sum after = 51.1575 25.68 sum before = 51.1575 sum after = 76.8375 25.585 sum before = 76.8375 sum after = 102.42250000000001 25.51 sum before = 102.42250000000001 sum after = 127.93250000000002 sum = 127.93250000000002
原因分析
多出的0.00000000000001本质是double类型的二进制精度限制导致的浮点数误差:
- double是64位浮点数,采用二进制存储十进制小数时,很多十进制小数(比如
0.005、0.01这类)无法被二进制精确表示,只能存储近似值。 - LINQ的
Sum()方法内部可能采用了优化的累加逻辑(比如Kahan求和算法),或者累加顺序与手动逆序不同,使得误差被抵消或最小化,最终结果显示为看似“精确”的127.9325。 - 手动逆序累加时,每一步的近似值误差会逐步累积,最终导致结果出现微小偏移。
解决办法(必须使用double类型)
格式化输出解决显示问题:
如果只是需要显示结果一致,可以对求和结果进行格式化,保留指定小数位数:// 保留4位小数,输出为127.9325 Debug.WriteLine("sum = " + sum.ToString("F4")); // 或者使用格式化字符串 Debug.WriteLine(string.Format("sum = {0:0.0000}", sum));实现Kahan求和算法减少误差:
Kahan求和算法可以在累加过程中补偿误差,大幅降低浮点数累加的误差累积,无论累加顺序如何,结果都会更接近真实值:double sum = 0.0; double error = 0.0; foreach (double num in deviations.GetRange(startIndex, Lenght)) { double temp = num - error; double newSum = sum + temp; error = (newSum - sum) - temp; sum = newSum; }统一累加顺序:
如果要求两种方式计算结果完全一致,可以让手动累加的顺序和LINQSum()的顺序相同(即正序累加),这样误差累积方向一致,结果会匹配。
内容的提问来源于stack exchange,提问作者КУдак
相关产品推荐
相关产品推荐

