试图模仿Excel四舍五入引起我的悲痛

该值是2.01和2.52之和除以2 (2.01 + 2.52) / 2 。 Excel将此值显示为2.265,格式为2位时为2.27。 但是,存储在文件中的值是2.2649999999999997。 当我重新创build这是C#,我也得到了我的variables,而不是2.265的价值。 我明白这是由于4.53除以2的浮点精度问题。

 double result = (2.01 + 2.52) / 2; Console.WriteLine(result); 

控制台显示2.265,但QuickWatchdebugging器中显示的值显示为2.264999999999997。 我怀疑在WriteLine方法中将值转换为string正在纠正浮点精度错误。

当我申请Math.Round(result, 2, MidpointRounding.AwayFromZero) ,结果如我所预期的那样回到2.26而不是2.27 。 它看起来像在我想四舍五入的数字右边的第一个数字,看到它是一个4,忽略了它的权利的一切。 问题在于那些9只是因为精度问题而需要包含的,或者更好一些,值应该是2.265

我在我的代码中所做的是从Excel电子表格"2.2649999999999997"读取文本值,将其转换为双2.264999999999999 ,然后转换为string,从而得到"2.265" 。 然后,我将其转换回2.265以便我可以将Math.Round应用到它,并得到2.27的预期结果。 以下是完整的代码:

 double result = Convert.ToDouble(((2.01 + 2.52) / 2).ToString()); Console.WriteLine(Math.Round(result, 2, MidpointRounding.AwayFromZero)); 

我的方法是浮点精度和舍入问题,依靠ToString来清理它,正确的? 如果不是,我该怎么做呢?

首先:问题很难。 因为4.53 / 2 = 2.265。 这轮到2.27。 然而计算中最小的四舍五入误差导致较小的结果(2.264999999 ….)将导致舍入到2.26。 这是在这里发生的事情。 要解决这个问题,你需要有一个浮点运算,它具有与Excel一样的内部舍入错误。

从这个文档https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel看起来好像Excel使用的是IEEE 754的修改版本,而C#使用IEEE 754.我不知道差异在哪里,但是看起来好像内部Excel生成不同的舍入错误。

本文档介绍了不同之处: https : //support.microsoft.com/en-us/kb/78113/en-us (例如,Excel不使用非规格化的数字。这意味着数字<2的舍入错误的不同行为)。

所以我认为你不能解决这个使用“双”

更新

但是,现在我明白这个问题不是算术,而是Excel显示数字的方式,也许这是一个解决scheme

 Math.Round(Math.Round(result, 3, MidpointRounding.AwayFromZero), 2, MidpointRounding.AwayFromZero) 

第一轮到3,然后到2位数字。 在我看来,Excel是这样做的。