问题描述
我正在为我的同事们做一次关于C#在Math.Round
函数中使用的Banker's Rounding方法的测验。但是在准备问题时,我得到了一个我觉得很奇怪的结果。最初,我使用数组,但是我设法将其简化为以下代码片段,以找到小型复制场景:
class MainClass {
public static void Main (string[] args) {
double x = 10.5;
System.Console.WriteLine(format: "Math.Round({0}) = {1}",arg0: x,arg1: System.Math.Round(x));
const double y = 10.5;
System.Console.WriteLine(format: "Math.Round({0}) = {1}",arg0: y,arg1: System.Math.Round(y));
}
}
这将产生以下输出:
Math.Round(10.5) = 10
Math.Round(10.5) = 11
(我也尝试过使用decimal
数字,这在计算方法之间没有任何区别:两者都得出10,根据银行家舍入规则是正确的。)
现在,我猜想这可能与const double
版本被预编译有关,但是我希望-而且我不确定这是否合理-预编译版本使用相同的规则四舍五入和/或(我不确定确切的原因是什么)遭受完全相同的舍入误差-实际上,我希望期望可以执行完全相同的计算,只是在不同的地方时间。
要找到有关此行为的更多信息有些困难,部分原因是我不确定我是否遇到Math.Round
中的错误(显然也存在一些问题)或其他问题与const
允许的预编译有关,但我猜是后者-搜索“ c#const different result”之类的东西并没有立即使我有用。
所以我的问题是,任何人都可以用以下方式解释此输出:“只有在编译器在X平台上运行,然后程序在Y平台上因为Z运行的情况下,这种情况才会发生?”
解决方法
我不确定这是否是mono编译器的错误,但是我遇到了类似的问题here,并且由贡献者here进行了代码更改。
我的猜测是,舍入功能将测试中的小数位更改为值 X ,但是使用常数 Y 时,原始值不会改变。 / p>
下面是一个可能的解决方法:
double x = 10.5;
const double y = 10.5;
System.Console.WriteLine(format: "Math.Round({0}) = {1}",arg0: x,arg1: System.Math.Round(x,MidpointRounding.AwayFromZero));
// 11
System.Console.WriteLine(format: "Math.Round({0}) = {1}",arg0: y,arg1: System.Math.Round(y,MidpointRounding.AwayFromZero));
// 11
System.Console.WriteLine(format: "Math.Round({0}) = {1}",MidpointRounding.ToEven));
// 10
System.Console.WriteLine(format: "Math.Round({0}) = {1}",MidpointRounding.ToEven));
// 10
我能够在Windows 10的x_86和x_64的.NET,.NET Core 3.0中正确执行Math.Round。
也许这是在mono github上报告的问题。如果这样做,可以在命令行窗口Repl.it上使用以下命令获取系统和编译器信息。
系统信息:uname -a
Linux 52d579a3a5fc 5.4.0-1019-gcp#19-Ubuntu SMP Tue Jun 23 15:46:40 UTC 2020 x86_64 x86_64 x86_64 GNU / Linux
编译器版本:mono --version
Mono JIT编译器版本6.10.0.104(tarball Fri Jun 26 19:38:24 UTC 2020) 版权所有(C)2002-2014 Novell,Inc.,Xamarin Inc和贡献者。 www.mono-project.com TLS:__thread SIGSEGV:altstack 通知:epoll 架构:amd64 禁用:无 其他:softdebug 口译员:是的 LLVM:是的(610) 挂起:混合 GC:sgen(默认为并发)
有趣的问题!请告诉我是否对您有帮助。