VB.net Math.Round舍入问题 - 对于相同输入的不同结果
问题描述:
我们遇到了VB.NET的Math.Round
方法的问题,我们得到的输入结果不同。问题是可再现的,并使用该短块的含有简单移动平均函数代码最佳地示出:VB.net Math.Round舍入问题 - 对于相同输入的不同结果
Public Class bug
Public Shared Function ExponentialMovingAverage(Values() As Double) As Double
Dim Weight, TotalWeight As Double
ExponentialMovingAverage = 0
Weight = 1
TotalWeight = 0
For Each Value In Values
ExponentialMovingAverage += Value*Weight
TotalWeight += Weight
Weight /= 1-2/(Values.Length+1)
Next
ExponentialMovingAverage /= TotalWeight
Return ExponentialMovingAverage
End Function
Public Shared Sub Main
Dim v As Double = 20.41985000000000000000
Console.WriteLine(_
ExponentialMovingAverage({77.474, 1.4018}).ToString("0.00000000000000000000") & " --> " & _
Math.Round(ExponentialMovingAverage({77.474, 1.4018}), 4) & vbCrLf & _
v.ToString("0.00000000000000000000") & " --> " & _
Math.Round(v, 4))
End Sub
End Class
运行该代码给出以下输出(培养NL-NL):
20,41985000000000000000 --> 20,4199
20,41985000000000000000 --> 20,4198
我们想知道为什么输出与Math.Round
的两个看似相同的调用有所不同。不应该有任何精度问题,因为所使用的值的位数少于15-16 digits,它应该适合Double
数据类型。
搜索网络主要返回与MidpointRounding
相关的舍入问题的答案,这似乎与此无关。
期待任何回复。
答
我怀疑这是因为,默认情况下,Math.Round使用ToEven
作为其舍入方法。如果你切换到:
Console.WriteLine(_
ExponentialMovingAverage({77.474, 1.4018}).ToString("0.00000000000000000000") & " --> " & _
Math.Round(ExponentialMovingAverage({77.474, 1.4018}), 4, MidpointRounding.AwayFromZero) & vbCrLf & _
v.ToString("0.00000000000000000000") & " --> " & _
Math.Round(v, 4, MidpointRounding.AwayFromZero))
然后结果如你所料。你的硬编码值正好是20.41985,所以ToEven
会变成20.4198。我怀疑你的计算结果比20.41985大得多(如上所述,结果我也得到了20.419850000000004),因此被四舍五入。
当我测试你的功能上面'ExponentialMovingAverage'产生的20.419850000000004 – OSKM
输出*您没有*具有相同的输入不同的结果。 'Math.Round()'是确定性的。你看起来相同的输入有不同的结果。底层浮点数位于底数2中。显示基数为10的基数为2的工件偶尔会显示不同的数字。看起来,VB.net不幸的是缺少一个内置的'frexp()',它可以让你轻松地检查底层的位模式,但是如果你好奇的话,应该很容易转换为vb:http:// stackoverflow。 COM/q /4996248分之389993 –