vivek.m
vivek.m

Reputation: 3331

C# Math.Round ambiguous issue

a,b are of type long

Math.Round(a/b, (int)2) 

The call is ambiguous between the following methods or properties: System.Math.Round(double, int) and System.Math.Round(double, System.MidpointRounding)

How to tell compiler that second argument is int and not System.MidpointRounding?

Edit 1: For some reason, if I run above code stand-alone, I get the error "Error CS0121 The call is ambiguous between the following methods or properties: 'Math.Round(double, int)' and 'Math.Round(decimal, int)' " but my original code runs as part of long script where a, b are implictly-typed intermediate variables and gives me above confusing error message.

There are two right answers:

  1. Use named parameter i.e. Math.Round(a/b, digits: 2) [thanks to colinB's comment]
  2. Cast to double (although this is not obvious from original error message) i.e. Math.Round((double)a/b, 2) [thanks to Owen Pauling's answer]

Upvotes: 1

Views: 1596

Answers (2)

Jan Heldal
Jan Heldal

Reputation: 176

Owen Pauling briefly touched upon this problem, but I feel it needs a bit more attention for future readers:

When both a and b are integer types (long in your case) then the result of the division itself is already an integer (implicitly rounded towards zero). This happens already before the call to Math.Round, which is too early to accomplish what you seem to want here.

So basically you are asking to round an integer to an integer, which of course does not make sense. This is why there is no Math.Round expecting integer typed numbers, which is why it requires casting and does not know what to cast it to.

To summarize: This looks like a common bug. You are not asking for what you think you are asking for, and the rounding will not behave as you want it to, unless you cast to your chosen non-integer type before dividing, like this:

double correct1 = Math.Round(a / (double)b, 2); // Owen Pauling's answer
decimal correct2 = Math.Round(a / (decimal)b, 2);

But do not merely circumvent the compilation error like this:

double inCorrect1 = Math.Round(a / b, digits: 2); // colinB's answer
decimal inCorrect2 = Math.Round(a / b, decimals: 2);

(Note: Because casting has a higher priority than division, it does not matter whether you cast the dividend or the divisor. I prefer casting the divisor because it makes it visually obvious that the casting is performed before the division.)

Upvotes: 0

Owen Pauling
Owen Pauling

Reputation: 11841

There's a couple of things wrong with your question. Before the edit, it showed two properties being divided to produce the first argument to Math.Round. I expect these values are integers, and therefore your result is not a double, but an integer. An integer can be implicitly cast to a double or a decimal. This leads to the second problem with the question, which is that the overload that is ambiguous is System.Math.Round(decimal, System.MidpointRounding). Basically, the compiler doesn't know if you're calling the overload with the double or the decimal.

You can fix this by making sure the result of the division is a double, eg:

Math.Round(val1/(double)val2, 2);

Upvotes: 3

Related Questions