I was setting up a pop quiz for my colleagues about the Banker's Rounding approach that C# uses in the Math.Round
function. But while preparing the question in repl.it I got a result that I thought was pretty weird. At first I was working with an array, but I've managed to boil it down to this snippet to find a small reproduction scenario:
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));
}
}
This results in the following output:
Math.Round(10.5) = 10
Math.Round(10.5) = 11
(I've also tried it with decimal
numbers, which didn't result in any difference between the calculation methods: both resulted in 10 which is correct according to the Banker's Rounding rule.)
Now, I'm guessing this might have something to do with the const double
version getting precompiled, but I'd expect - and I'm not sure this is reasonable - the precompiled version to use the same rules for rounding and/or (I'm not sure what the exact cause is) suffer from the exact same roundoff error - effectively, I'd expect it to perform the exact same calculation, just at a different time.
It is somewhat hard to find more information on this behavior, partially because I'm not sure whether I've ran into a bug in Math.Round
(which is, apparently, has some issues as well) or something that is related to the precompilation that const
s allow, but I'm guessing it's the latter - and searching for things like "c# const different result" gave me nothing immediately useful.
So my question is, can anyone explain this output in terms of "this only happens if the compiler runs on platform X and the program then runs on platform Y because Z"?
(Edit: sorry, forgot to post the repl.it link. Here it is!)
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.
Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.
Because a and b and c , so it's name is C. C came out of Ken Thompson's Unix project at AT&T. He originally wrote Unix in assembly language. He wrote a language in assembly called B that ran on Unix, and was a subset of an existing language called BCPL.
I'm not sure if this is a bug with the mono compiler, but I encountered a similar problem here, and the code change that was made by the contributor here.
My guess is that the Round function is changing the decimal places in the tests to the value X, but with the constant Y the original value does not change.
Below is a possible workaround:
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
I was able to do Math.Round correctly in .NET, .NET Core 3.0 in both x_86 and x_64 on windows 10.
Perhaps it is something to report on the mono github as a issue. If you do, you can get the system and compiler information with the below commands in the command line window at Repl.it
System info: 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
Complier version: mono --version
Mono JIT compiler version 6.10.0.104 (tarball Fri Jun 26 19:38:24 UTC 2020) Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. 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)
Interesting question! please let me know if it helped you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With