Skip to main content
gamedev.net
🔒 Locked

Testing for integer overflow

Started by Rattrap Aug 26, 2005 at 3:50 PM 27 replies 4k views
Original Post
Rattrap
Rattrap
Is there any fast and fairly machine independant methods of testing to see if adding to integers together would result in an overflow (going beyond the bit limit). example

char c1 = 255;
char c2 = 255;

char result = c1 + c2;

Result is going to result in 254, since the char can't hold it resulting value. Now I will say, I'm not also don't want to use a bigger sized variable to catch the overflow, since in the code I'm writting I will be using the largest primitive variables available.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
SiCrane
SiCrane
Try checking if the result is less than the addends.
doynax
doynax
Quote:
Original post by SiCrane
Try checking if the result is less than the addends.
In fact checking if it's smaller than one of them is enough.
if(c1 += c2, c1 < c2) { ..overflow.. }
Rattrap
Rattrap
Thanks for the fast responses.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
Anon Mike
Anon Mike
Be careful, that trick only works for unsigned types. And char is usually signed by default. If you turn up the warning level for your compiler it will probably complain about assigning 255 to a char.

I don't know of any fully general non-annoying way to test integer overflow that takes into account signed types.
-Mike
iMalc
iMalc
With twos-complment, to do the overflow check for signed types, you can simply cast them to the unsigned type (of the same size) first.
bool additionWouldOverFlow(unsigned char a, unsigned char b){    return (a + b) < b;}bool additionWouldOverFlow(signed char a, signed char b){    return additionWouldOverFlow((unsigned char)a, (unsigned char)b);}
Edit: It seems that my comment above was incorrect. My appologies.

[Edited by - iMalc on August 27, 2005 3:19:07 AM]
Anon Mike
Anon Mike
Nope. Consider the 8-bit signed addition of 5 plus 125 as translated into unsigned 8-bit addition:
(a + b) < b(5 + 125) < 125130 < 125           (we get 130 instead of -126 because of the unsigned conversion)== false

However the maximum for signed 8-bit two's complement is 127 so additionWouldOverflow should have returned true.
-Mike
Horatius83
Horatius83
You might consider using assembly to add the two and check the overflow bit, not machine independant, but you will know for sure.
"Think you Disco Duck, think!" Professor Farnsworth
Nathan Baum
Nathan Baum
Types shorter than int are always promoted to int before performing arithmetic operations -- that's one of what the standard calls the usual arithmetic conversions. So for testing overflow of those types, it suffices to test if the result is out of the range of the intended target type. For example, ((unsigned char) 255) + ((unsigned char) 255) produces 510. (Obviously, you can only do that before you put the result back into a char variable.)

In the event that you doubt that chars are promoted to ints, see what the following gets you:
std::cout << ('a' + 'b');


For int, the result is never automatically promoted. As already noted, for unsigned ints it suffices to determine if the result is less than either of the operands. For signed ints, it's a little more tricky.

bool would_overflow (signed char a, signed char b){  signed char c = a;  if (a > 0 && b > 0)    // The sum of positive numbers can't be less than any of the numbers.    return (c += b) < a;  else if (a < 0 && b < 0)    // The sum of negative numbers can't be greater than any of the numbers.    return (c += b) > a;  else    // A negative and positive addition cannot overflow.    return false;}
Nathan Baum
Nathan Baum
Quote:
Original post by Deyja
The result of your original code is -2, well within the range of chars.

How do you work that out?

Either you're being dumb and not noticing that 255+255 isn't -2, or you're trying to be clever and noting that when 255 is stored in a signed char, the result is -1 and -1 + -1 is -2.

Either way, you're wrong. The plain "char" type might be unsigned, in which case -2 is most certainly not within its range. As the standard says

Quote:

It is implementation-defined whether a char object can hold negative values.
Nathan Baum
Nathan Baum
From a standards-compliance POV, the consequences of integer overflow on signed integers is undefined. So any solution which involves doing (a + b) and examining the result has undefined behaviour. On most platforms, you can rely upon the right thing happening, but it's possible that some esoteric platform might signal an error or, worse, silently do the wrong thing.

For the sake of argument, here's a version of would_overflow whose behaviour is fully defined (I think).

#include <limits>bool would_overflow (signed char a, signed char b){  signed char max = std::numeric_limits<signed char>::max();  signed char min = std::numeric_limits<signed char>::min();  if ((a > max / 2) && (b > max / 2))      // If both a and b are greater than half the maximum value,      // the result MUST be greater than the maximum value.      return true;  else if ((a < min / 2) && (b < min / 2))      // If both a and b are less than half the minimum value,      // the result MUST be less than the minimum value.      return true;  else    // Otherwise the result MUST be within [minimum value, maximum value].    return false;}


As Knuth would say: Beware of bugs in the above code, I have only proven it correct, not tested it.
Promit
Promit
VC defaults char to be unsigned, whereas GCC defaults char to be signed. This can tend to lead to a few nasty platform bugs if you're not careful.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Rattrap
Rattrap
I was using chars as examples because they were small. In the code I want to do, I will be using the largest availabe primitive integer types. So like I said in the original post, casting up to a largest integer type is not really an option.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
Rattrap
Rattrap
Oh and just for reference; char, signed char, and unsigned char are technically 3 different types. The default signed/unsigned applied to just char doesn't actually make it the same as the respective signed char or unsigned char.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
Tim Cowley
Tim Cowley
Quote:
Original post by Promit
VC defaults char to be unsigned, whereas GCC defaults char to be signed. This can tend to lead to a few nasty platform bugs if you're not careful.

I have VC2003, and I'm pretty sure char is signed. Was it different in VC6?
Enigma
Enigma
Quote:
Original post by Nathan Baum
#include <limits>bool would_overflow (signed char a, signed char b){  signed char max = std::numeric_limits<signed char>::max();  signed char min = std::numeric_limits<signed char>::min();  if ((a > max / 2) && (b > max / 2))      // If both a and b are greater than half the maximum value,      // the result MUST be greater than the maximum value.      return true;  else if ((a < min / 2) && (b < min / 2))      // If both a and b are less than half the minimum value,      // the result MUST be less than the minimum value.      return true;  else    // Otherwise the result MUST be within [minimum value, maximum value].    return false;}

As Knuth would say: Beware of bugs in the above code, I have only proven it correct, not tested it.

Assuming an 8 bit twos-complement signed char:
signed char a = 120;signed char b = 30;if (would_overflow(a, b)){	std::cout << int(a) << " + " << int(b) << " would overflow a signed char.\n";}else{	std::cout << int(a) << " + " << int(b) << " = " << int(static_cast< signed char >(a + b)) << '\n';}

Enigma
Promit
Promit
Quote:
Original post by Tim Cowley
Quote:
Original post by Promit
VC defaults char to be unsigned, whereas GCC defaults char to be signed. This can tend to lead to a few nasty platform bugs if you're not careful.

I have VC2003, and I'm pretty sure char is signed. Was it different in VC6?


Ah, that might be. I haven't bothered to test in a while.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Rattrap
Rattrap
The char things can be manipulated in the settings. But this came up in a different thread. Lets say char is signed by default. char and signed char are still 2 different types as far as the Visual C++ is concerned, I actually learned this after reporting at casting problem involving it too the beta team on VS2005. They basically responded that the standard distinguishes between char, unsigned char, and signed char.
"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]
Nathan Baum
Nathan Baum
Quote:
Original post by Enigma
Quote:
Original post by Nathan Baum
[ snip broken code... ]
As Knuth would say: Beware of bugs in the above code, I have only proven it correct, not tested it.

Assuming an 8 bit twos-complement signed char:

My Knuth quote was truer than I suspected. I realised as I was walking to work this afternoon that my function is badly wrong.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.