首页 > 解决方案 > C# 计算在 const 和 variable locals 之间有什么不同?

问题描述

我正在为我的同事设置一个关于 C# 在Math.Round函数中使用的银行家舍入方法的流行测验。但是在 repl.it 中准备问题时,我得到了一个我认为很奇怪的结果。起初我正在使用一个数组,但我设法将其归结为这个片段以找到一个小的复制场景:

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预编译的版本有关,但我希望 - 我不确定这是合理的 - 预编译版本使用相同的舍入规则和/或(I'我不确定确切的原因是什么)遭受完全相同的舍入误差 - 实际上,我希望它执行完全相同的计算,只是在不同的时间。

很难找到有关此行为的更多信息,部分原因是我不确定我是否遇到了错误Math.Round(显然也有一些问题)或与预编译相关const的问题允许,但我猜是后者——搜索“c# const different result”之类的东西没有给我任何立即有用的东西。

所以我的问题是,任何人都可以用“只有当编译器在平台 X 上运行并且程序然后因为 Z 在平台 Y 上运行时才会发生这种情况”来解释这个输出?

(编辑:抱歉,忘记发布 repl.it 链接。在这里!)

标签: c#monoconstantsdouble

解决方案


我不确定这是否是单声道编译器的错误,但我在这里遇到了类似的问题,以及贡献者在此处所做的代码更改。

我的猜测是 Round 函数将测试中的小数位更改为值X,但使用常量Y时,原始值不会改变。

以下是一种可能的解决方法:

double x = 10.5;
const double y = 10.5;

System.Console.WriteLine(format: "Math.Round({0}) = {1}",
                         arg0: x,
                         arg1: System.Math.Round(x, 0, MidpointRounding.AwayFromZero));
// 11
System.Console.WriteLine(format: "Math.Round({0}) = {1}",
                         arg0: y,
                         arg1: System.Math.Round(y, 0 , MidpointRounding.AwayFromZero)); 
// 11
System.Console.WriteLine(format: "Math.Round({0}) = {1}",
                         arg0: x,
                         arg1: System.Math.Round(y, 0 , MidpointRounding.ToEven));
// 10
System.Console.WriteLine(format: "Math.Round({0}) = {1}",
                         arg0: y,
                         arg1: System.Math.Round(y, 0 , MidpointRounding.ToEven));
// 10

我能够在 Windows 10 上的 x_86 和 x_64 中的 .NET、.NET Core 3.0 中正确执行 Math.Round。

也许将单声道 github 报告为一个问题。如果这样做,您可以在 Repl.it 的命令行窗口中使用以下命令获取系统和编译器信息

系统信息:uname -a

Linux 52d579a3a5fc 5.4.0-1019-gcp #19-Ubuntu SMP 2020 年 6 月 23 日星期二 15:46:40 UTC x86_64 x86_64 x86_64 GNU/Linux

编译器版本:mono --version

Mono JIT 编译器版本 6.10.0.104(tarball,2020 年 6 月 26 日星期五 19:38:24 UTC) 版权所有 (C) 2002-2014 Novell, Inc、Xamarin Inc 和贡献者。www.mono-project.com TLS: __thread SIGSEGV: altstack Notifications: epoll Architecture: amd64 Disabled: none Misc: softdebug Interpreter: yes LLVM: yes(610) Suspend: hybrid GC: sgen (concurrent by default)

有趣的问题!请让我知道它是否对您有帮助。


推荐阅读