11

I'm using

Decimal.Round(decimal d)

MSDN says it can throw OverflowException https://msdn.microsoft.com/en-us/library/k4e2bye2(v=vs.110).aspx

I'm not sure how that can happen. I tried looking over the implementation using ilSpy And got until the external implementation of:

// decimal
[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void FCallRound(ref decimal d, int decimals);

Does anybody got a clue what input can throw this exception?

6
  • 5
    stackoverflow.com/questions/3203959/… Commented Feb 20, 2017 at 15:48
  • 4
    FWIW, this is where that target call is implemented in the .NET Core CLR - you can see the throw of OverflowException on line 188. Commented Feb 20, 2017 at 15:48
  • 3
    And this appears to be the implementation of VarDecRound. At first glance, I can't see why it would return a failure result to FCallRound (resulting in the exception being thrown). It either returns E_INVALIDARG, but the condition for that has already been checked by FCallRound, or NOERROR, so it seems that the OverflowException shouldn't actually ever be thrown. Commented Feb 20, 2017 at 15:51
  • 11
    It will never happen. The specification for the automation function is not very good, it does not document what kind of failure codes it can return. So the CLR authors just assume that, if it fails, then it could only be because of overflow. Won't happen, Decimal.Min/MaxValue are integral values. Also visible from the Unix version of VarDecRound: github.com/dotnet/coreclr/blob/master/src/palrt/… Commented Feb 20, 2017 at 16:55
  • 8
    @HansPassant: In the 1990s I had the office next to the guys who wrote that library and they jokingly referred to the documentation (which was of course on paper back then) as "the book of lies". That documentation indeed was not great, and no one has improved it in the last 20+ years apparently. Commented Feb 20, 2017 at 17:06

1 Answer 1

3

When we go further from what you already discovered yourself, we end up in the implementation of the VarDecRound function. This function has exactly one branch where it returns an error code, and that is when its second argument cDecimals is smaller than zero. This argument indicates the number of decimal digits to round to:

if (cDecimals < 0) 
    return E_INVALIDARG; 

(this kind of assertion is the equivalent of what an ArgumentException would be in .NET)

As James Thorpe pointed out in a comment on OP, a similar assertion is done further up the call chain, here:

if (decimals < 0 || decimals > 28) 
    FCThrowArgumentOutOfRangeVoid(...)

Conclusion:
Execution cannot reach the point that would result in throwing the OverflowException as documented:

  1. OverflowException seems to have been used internally as a catch-all mechanism, much like OutOfMemoryException in GDI+
  2. The documentation does not match the actual implementation
  3. OverflowException does not even make sense conceptually. Rounding a value up or down in the same data type cannot possibly exceed an integral min or max range, because the candidate value must itself be in range (rounding method used)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.