Math.round bug – 该怎么办?
Math.Round(8.075, 2, MidpointRounding.AwayFromZero)
返回8.07
,但它应该返回8.08
。 神奇的是, 7.075
工作正常,但9.075
也返回9.07
!
该怎么办? 有没有人知道没有这些错误的舍入方法?
如果算上10个手指,就像人类一样,那么精确地表达小数值8.075没有任何问题:
8.075 = 8 x 10^1 + 0 x 10^0 + 7 x 10^-1 + 5 x 10^-2
但计算机只能用2个手指计数,它们需要以2的幂表示该值:
8.075 = 1 x 2^3 + 0 x 2^2 + 0 x 2^1 + 0 x 2^0 + 0 x 2^-1 + 0 x 2^-2 + 0 x 2^-3 + 1 x 2^-4 + 0 x 2^-5 + 0 x 2^-6 + 1 x 2^-7 + 1 x 2^-8 + 0 x 2^-9 + 0 x 2^-10 + 1 x 2^-11 + ...
我放弃了手指抽筋输入术语,但重点是无论你添加多少2的力量,你永远不会得到8.075米。 一个类似的问题,人类如何不能精确地写出10/3的结果,它在分数中有无数个数字。 只有6个手指计数时,才能准确地写出该表达式的结果。
处理器当然没有足够的存储空间来存储无限数量的位来表示值。 所以他们必须截断数字序列,double类型的值可以存储53位。
结果,当十进制值8.075存储在处理器中时,它将被舍入。 转换回十进制的53位序列是值~8.074999999999999289。 然后,正如预期的那样,您的代码将四舍五入到8.07。
如果你想要10个手指数学结果,你需要使用一个数据类型来存储基数为10.这就是.NET中的System.Decimal类型。 固定:
decimal result = Math.Round(8.075m, 2, MidpointRounding.AwayFromZero)
请注意代码段中8.075m文字中字母m的用法,即十进制的文字。 选择使用10个手指计数的Math.Round()重载,之前您使用了使用System.Double(2个手指版本)的重载。
请注意,使用System.Decimal进行计算有一个明显的缺点,它很慢 。 比使用System.Double计算要慢很多,这是处理器直接支持的值类型。 十进制数学在软件中完成,而不是硬件加速。
我不是.net专家,但这些数字不能完全表示为double,因此如果考虑到这3个数字的实际值,则舍入是准确的:
7.075 ==> 7.07500000000000017763568394002504646778106689453125 8.075 ==> 8.074999999999999289457264239899814128875732421875 9.075 ==> 9.074999999999999289457264239899814128875732421875
关于浮点精度的更多信息: 每个计算机科学家应该知道的浮点运算 。
可能的解决方案可能是:
(double)Math.Round((decimal)8.075, 2, MidpointRounding.AwayFromZero);
- 如何只读取Windows窗体控件?
- 将Trace方法添加到System.Diagnostics.TraceListener
- LinQ WHERE string.Contains还是string.IndexOf?
- 使用SignalR时,mscorlib.dll中出现“System.AggregateException”
- 在C#.NET中设置NTFS权限
- 来自c#的PInvoke c ++ dll – 尝试加载格式不正确的程序。 (HRESULTexception:0x8007000B)
- 使用.net中用户错误报告的行号重新创建堆栈跟踪?
- 如何使用C#中的Json.NET从JSON访问嵌套对象
- 我可以定义具有相同名称但不同参数的2个代理吗?