2

I am getting OverflowException's thrown at me when I don't want them (or so I think). I am performing some odd calculations where I expect the values to overflow, discarding overflowed bits. It seems I can't get this to work properly though. Basically this is one pair of i and j which happens as I iterate over huge sets (int.MinValue to int.MaxValue).

// i and j are ints
// i is -2147483648
// j is -1
var x = i / j;

// I also tried using unchecked keyword, but it doesn't help    
var x = unchecked(i / j);

Update:

The expected mathematic value of -2147483648 / -1 is 2147483648. However, this certain code doesn't really attempt to find the number. This is part of a series of bit manipulation things gone a bit hard to understand. To be honest, I don't even know myself what the intention was because I didn't really document the method, and all it took was one day away from it to raise serious WTF-bubbles over my head. All I know it works as intended with special code designed to handle the case.

About the expected value:

Since int can only hold 2147483647 at it's max, I expect to discard the overflow yielding value 0.

If I've learned anything about this at all, it's probably the importance of documentation for obscure methods.

Statement
  • 3,888
  • 3
  • 36
  • 45
  • 3
    I do hope you have a try/catch block around this in the real code? – Traveling Tech Guy Aug 19 '09 at 15:39
  • No, I don't. However, I do make sure I don't divide with zero. – Statement Aug 20 '09 at 11:30
  • Regarding your edit: Would you expect `int.MaxValue + 1`, which also equals 2147483648, to overflow to zero? – LukeH Aug 20 '09 at 11:59
  • No, I wouldn't. Anyhow, I suppose I already solved the issue (though I don't think it's neat to have a check for it). Thanks for your help. In case anyone comes up with a "clean" solution for the expected behaviour, feel free to post it. – Statement Aug 20 '09 at 21:26

4 Answers4

6

I believe this is the only case in which you'll get this exception. It's the only division within the Int32 range which can overflow. (There's division by zero of course, but that's a different exception.)

So if you want to avoid OverflowException you only need to deal with this case. What do you want it to do? Write a method which spots this exact case, and otherwise does normal division.

Note: this is also why you shouldn't try to reverse a comparison by just negating the result. If you want to sort something in descending order instead of ascending, then instead of using -Compare(x, y) use Compare(y, x). The negation doesn't give overflow for int.MinValue (unless you're in a checked context) - it just silently returns int.MinValue.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • From your post I understand, that negating int.MaxValue returns int.MinValue, instead of overflowing, but negating int.MaxValue returns int.MinValue + 1 as it should (cause range is between 2147483647 and -2147483648). Also, negating int.MinValue is a place where it should overflow, but than - c# happily returns int.MinValue again (or throws inside checked{}). Have I misunderstood your point, or is it a typo? – Marcin Deptuła Aug 19 '09 at 16:01
  • Typo - that MaxValue should have been MinValue. – Jon Skeet Aug 19 '09 at 16:32
3

Twos complement means that integers will range from 2^32 - 1 to -2^32, so -2147483648 / -1 is returning a number which can't be represented by an int.

You could try putting it into a long. There's no reason to use a var in this situation.

Pike65
  • 562
  • 2
  • 6
  • 1
    Actually, doing something like this: x = i / j;, where x is long won't help, whole operation must be performed on long, so x = (long)i / j; will work, and because result will be long, here var can be used (although I personally don't like using var in such context, but that's whole different story. – Marcin Deptuła Aug 19 '09 at 15:45
  • 4
    I'm pretty sure the OP knows this. His problem is that unchecked doesn't work the way it should. The only exception that unchecked should allow is div by 0. Whether x is int or var does not matter in this example. – Rado Aug 19 '09 at 15:50
0

You can workaround this with a bit of casting to/from Int64:

var x = (int)((long)i / j);
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • Doesn't work. `x` ends up with `-2147483648`, and the right answer is `2147483648`. As **Pike65** correctly pointed out, this number can't be represented in a signed 32 bit integer. The only way to solve this problem is by using some other type, like `long`. – jpbochi Aug 19 '09 at 16:22
  • 2
    @jpbochi: The OP is expecting it to overflow, and wants it to do so without an exception being thrown. The "overflowed" `Int32` equivalent of 2147483648 is -2147483648. – LukeH Aug 19 '09 at 16:29
  • @jpbochi, Try this: `var x = unchecked(int.MaxValue + 1);` – LukeH Aug 19 '09 at 16:32
0

You do this. Why would you use var here? It loses the ability to show you the type of arithmetic result all for saving 1 character...

long x = (long)i / j;

If you want saturation, you can:

int x = (int)Math.Min((long)i / j, int.MaxValue);
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • The question suggests that the OP expects the result to be an "overflowed" `int`, not a `long`: "I expect the values to overflow, discarding overflowed bits". – LukeH Aug 19 '09 at 16:44
  • 1
    To be honest, having var or int is irrelevant because the evaulation of the types will cause var to take the type of int. I chose var in case I would have to write similar code for long, where I wouldn't have to refactor alot if I used var. – Statement Aug 20 '09 at 11:35