Issue with "arithmetic operation resulted in overflow"

I have this expression

 long balance = (long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD();

which raises exception that there was overflow. The value on the right hand side is of unsigned type and has value: 18446744073708240732.

How to avoid this exception, use unchecked?

PS equivalent C++ implementation returned balance = -1310984, I need same value here too.

Why is there such an exception?


By using unchecked indeed now also on C# side I get -1310984. Can someone advice, am I losing data somehow?

Jon Skeet
people
quotationmark

Given the comments, it sounds like you do just need to use unchecked arithmetic - but you should be concerned about the use of ulong in your API. If your aim is to just propagate 8 bytes of data, and interpret it as either an unsigned integer or a signed integer depending on context, then you're fine - so long as nothing performs arithmetic on it in the "wrong" form.

It's important to understand why this happens though, and it's much easier to explain that with small numbers. I'll use byte and sbyte as an example. The range of byte is 0 to 255 inclusive. The range of sbyte is -128 to 127 inclusive. Both can store 256 different values. No problem.

Now, using unchecked conversions, it's fine to say:

byte a = GetByteFromSomewhere();
sbyte b = (sbyte) a;
StoreSByteSomewhere(b);
...
sbyte b = GetSByteFromStorage();
byte a = (byte) b;

If that's all you're doing, that's fine. A byte value of -1 will become an sbyte value of 255 and vice versa - basically it's just interpreting the same bit pattern in different ways.

But if you're performing other operations on the value when it's being handled as the "wrong" type, then you could get unexpected answers. For example, consider "dividing by 3". If you divide -9 by 3, you get -3, right? Whereas if you have:

byte original = -9;
sbyte converted = (sbyte) original;
sbyte divided = converted / 3;
byte result = (byte) divided;

... then you end up with a result of -2 instead of -3, due to the way the arithmetic worked.

Now that's all for unchecked conversions. When you have a checked conversion, it doesn't just interpret the bits - it treats the value as a number instead. So for example:

// In a checked context...
byte a = 128;
sbyte b = (sbyte) a; // Bang! Exception

That's because 128 (as a number) is outside the range of sbyte. This is what's happening in your case - the number 18446744073708240732 is outside the range of long, so you're getting an exception. The checked conversion is treating it as a number which can be range-checked, rather than an unchecked conversion just reinterpreting the bits as a long (which leads to the negative number you want).

people

See more on this question at Stackoverflow