The %d conversion specifier in the format string of printf converts the corresponding argument to a signed decimal integer, which in this case, overflows for the int type. C standard specifically mentions that signed integer overflow is undefined behaviour. What you should do is to use %u in the format string. Also, you need to include the headers stdio.h and stdlib.h for the prototype of the functions printf and abs respectively.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// This solves the issue of using the standard abs() function
unsigned int absu(int value) {
return (value < 0) ? -((unsigned int)value) : (unsigned int)value;
}
int main(void) {
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
printf("absu(INT_MIN): %u\n", absu(INT_MIN));
return 0;
}
This gives the output on my 32-bit machine:
INT_MAX: 2147483647
INT_MIN: -2147483648
absu(INT_MIN): 2147483648
Answer from ajay on Stack OverflowThe %d conversion specifier in the format string of printf converts the corresponding argument to a signed decimal integer, which in this case, overflows for the int type. C standard specifically mentions that signed integer overflow is undefined behaviour. What you should do is to use %u in the format string. Also, you need to include the headers stdio.h and stdlib.h for the prototype of the functions printf and abs respectively.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// This solves the issue of using the standard abs() function
unsigned int absu(int value) {
return (value < 0) ? -((unsigned int)value) : (unsigned int)value;
}
int main(void) {
printf("INT_MAX: %d\n", INT_MAX);
printf("INT_MIN: %d\n", INT_MIN);
printf("absu(INT_MIN): %u\n", absu(INT_MIN));
return 0;
}
This gives the output on my 32-bit machine:
INT_MAX: 2147483647
INT_MIN: -2147483648
absu(INT_MIN): 2147483648
How about
printf ("abs(INT_MIN) = %ld", -((long int) INT_MIN));
Or if your long is not longer than an int:
printf ("abs(INT_MIN) = %lld", -((long long int) INT_MIN));
Or if you are prepared to accept that abs(INT_MIN) is always INT_MAX + 1:
printf ("abs(INT_MIN) = %u", ((unsigned int) INT_MAX ) + 1 );
Videos
Integer.MIN_VALUE is -2147483648, but the highest value a 32 bit integer can contain is +2147483647. Attempting to represent +2147483648 in a 32 bit int will effectively "roll over" to -2147483648. This is because, when using signed integers, the two's complement binary representations of +2147483648 and -2147483648 are identical. This is not a problem, however, as +2147483648 is considered out of range.
For a little more reading on this matter, you might want to check out the Wikipedia article on Two's complement.
The behaviour you point out is indeed, counter-intuitive. However, this behaviour is the one specified by the javadoc for Math.abs(int):
If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned.
That is, Math.abs(int) should behave like the following Java code:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
That is, in the negative case, -x.
According to the JLS section 15.15.4, the -x is equal to (~x)+1, where ~ is the bitwise complement operator.
To check whether this sounds right, let's take -1 as example.
The integer value -1 is can be noted as 0xFFFFFFFF in hexadecimal in Java (check this out with a println or any other method). Taking -(-1) thus gives:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
So, it works.
Let us try now with Integer.MIN_VALUE . Knowing that the lowest integer can be represented by 0x80000000, that is, the first bit set to 1 and the 31 remaining bits set to 0, we have:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
And this is why Math.abs(Integer.MIN_VALUE) returns Integer.MIN_VALUE. Also note that 0x7FFFFFFF is Integer.MAX_VALUE.
That said, how can we avoid problems due to this counter-intuitive return value in the future?
We could, as pointed out by @Bombe, cast our
ints tolongbefore. We, however, must either- cast them back into
ints, which does not work becauseInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE). - Or continue with
longs somehow hoping that we'll never callMath.abs(long)with a value equal toLong.MIN_VALUE, since we also haveMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
- cast them back into
We can use
BigIntegers everywhere, becauseBigInteger.abs()does indeed always return a positive value. This is a good alternative, though a bit slower than manipulating raw integer types.We can write our own wrapper for
Math.abs(int), like this:
/**
* Fail-fast wrapper for {@link Math#abs(int)}
* @param x
* @return the absolute value of x
* @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
*/
public static int abs(int x) throws ArithmeticException {
if (x == Integer.MIN_VALUE) {
// fail instead of returning Integer.MAX_VALUE
// to prevent the occurrence of incorrect results in later computations
throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
}
return Math.abs(x);
}
- Use a integer bitwise AND to clear the high bit, ensuring that the result is non-negative:
int positive = value & Integer.MAX_VALUE(essentially overflowing fromInteger.MAX_VALUEto0instead ofInteger.MIN_VALUE)
As a final note, this problem seems to be known for some time. See for example this entry about the corresponding findbugs rule.
The standard says about abs():
The
abs,labs, andllabsfunctions compute the absolute value of an integerj. If the result cannot be represented, the behavior is undefined.
And the result indeed cannot be represented because the 2's complement representation of signed integers isn't symmetric. Think about it... If you have 32 bits in an int, that gives you 232 distinct values from INT_MIN to INT_MAX. That's an even number of values. So, if there's only one 0, the number of values greater than 0 cannot be the same as the number of values less than 0. And so there's no positive counterpart to INT_MIN with a value of -INT_MIN.
So, what's unacceptable is calling abs(INT_MIN) on your platform.
Negative numbers are usually represented whit binary complement.
To convert positive to negative it is used logic
x -> not(x)+1
For 8 bits arithmetic
01111111b is 127 and -127 becomes
10000000b + 1 = 10000001b
and to opposite direction -127
10000001b becomes
01111110b + 1 = 01111111b
What about -128?
-128 is 10000000b and there is no positive counterpart of it, because there is no 128 in 8 bits signed arithmetic.
10000000 -> 01111111 + 1 = 10000000 and -128 again
Same applies to original question
Same as existing answers, but with more explanations:
Let's assume a twos-complement number (as it's the usual case and you don't say otherwise) and let's assume 32-bit:
First, we perform an arithmetic right-shift by 31 bits. This shifts in all 1s for a negative number or all 0s for a positive one (but note that the actual >>-operator's behaviour in C or C++ is implementation defined for negative numbers, but will usually also perform an arithmetic shift, but let's just assume pseudocode or actual hardware instructions, since it sounds like homework anyway):
mask = x >> 31;
So what we get is 111...111 (-1) for negative numbers and 000...000 (0) for positives
Now we XOR this with x, getting the behaviour of a NOT for mask=111...111 (negative) and a no-op for mask=000...000 (positive):
x = x XOR mask;
And finally subtract our mask, which means +1 for negatives and +0/no-op for positives:
x = x - mask;
So for positives we perform an XOR with 0 and a subtraction of 0 and thus get the same number. And for negatives, we got (NOT x) + 1, which is exactly -x when using twos-complement representation.
Set the mask as right shift of integer by 31 (assuming integers are stored as two's-complement 32-bit values and that the right-shift operator does sign extension).
mask = n>>31XOR the mask with number
mask ^ nSubtract mask from result of step 2 and return the result.
(mask^n) - mask
While the typical value of INT_MIN is -2147483648, and the typical value of INT_MAX is 2147483647, it is not guaranteed by the standard. TL;DR: The value you're searching for is INT_MAX in a conforming implementation. But calculating min(INT_MAX, abs(INT_MIN)) isn't portable.
The possible values of INT_MIN and INT_MAX
INT_MIN and INT_MAX are defined by the Annex E (Implementation limits) 1 (C standard, C++ inherits this stuff):
The contents of the header are given below, in alphabetical order. The minimum magnitudes shown shall be replaced by implementation-defined magnitudes with the same sign. The values shall all be constant expressions suitable for use in #if preprocessing directives. The components are described further in 5.2.4.2.1.
[...]
#define INT_MAX +32767
#define INT_MIN -32767[...]
The standard requires the type int to be an integer type that can represent the range [INT_MIN, INT_MAX] (section 5.2.4.2.1.).
Then, 6.2.6.2. (Integer types, again part of the C standard), comes into play and further restricts this to what we know as two's or ones' complement:
For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; signed char shall not have any padding bits. There shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M ≤ N). If the sign bit is zero, it shall not affect the resulting value. If the sign bit is one, the value shall be modified in one of the following ways:
— the corresponding value with sign bit 0 is negated (sign and magnitude);
— the sign bit has the value −(2M) (two’s complement);
— the sign bit has the value −(2M − 1) (ones’ complement).
Section 6.2.6.2. is also very important to relate the value representation of the signed integer types with the value representation of its unsigned siblings.
This means, you either get the range [-(2^n - 1), (2^n - 1)] or [-2^n, (2^n - 1)], where n is typically 15 or 31.
Operations on signed integer types
Now for the second thing: Operations on signed integer types, that result in a value that is not within the range [INT_MIN, INT_MAX], the behavior is undefined. This is explicitly mandated in C++ by Paragraph 5/4:
If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.
For C, 6.5/5 offers a very similar passage:
If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.
So what happens if the value of INT_MIN happens to be less than the negative of INT_MAX (e.g. -32768 and 32767 respectively)? Calculating -(INT_MIN) will be undefined, the same as INT_MAX + 1.
So we need to avoid ever calculating a value that may isn't in the range of [INT_MIN, INT_MAX]. Lucky, INT_MAX + INT_MIN is always in that range, as INT_MAX is a strictly positive value and INT_MIN a strictly negative value. Hence INT_MIN < INT_MAX + INT_MIN < INT_MAX.
Now we can check, whether, INT_MAX + INT_MIN is equal to, less than, or greater than 0.
`INT_MAX + INT_MIN` | value of -INT_MIN | value of -INT_MAX
------------------------------------------------------------------
< 0 | undefined | -INT_MAX
= 0 | INT_MAX = -INT_MIN | -INT_MAX = INT_MIN
> 0 | cannot occur according to 6.2.6.2. of the C standard
Hence, to determine the minimum of INT_MAX and -INT_MIN (in the mathematical sense), the following code is sufficient:
if ( INT_MAX + INT_MIN == 0 )
{
return INT_MAX; // or -INT_MIN, it doesn't matter
}
else if ( INT_MAX + INT_MIN < 0 )
{
return INT_MAX; // INT_MAX is smaller, -INT_MIN cannot be represented.
}
else // ( INT_MAX + INT_MIN > 0 )
{
return -INT_MIN; // -INT_MIN is actually smaller than INT_MAX, may not occur in a conforming implementation.
}
Or, to simplify:
return (INT_MAX + INT_MIN <= 0) ? INT_MAX : -INT_MIN;
The values in a ternary operator will only be evaluated if necessary. Hence, -INT_MIN is either left unevaluated (therefore cannot produce UB), or is a well-defined value.
Or, if you want an assertion:
assert(INT_MAX + INT_MIN <= 0);
return INT_MAX;
Or, if you want that at compile time:
static_assert(INT_MAX + INT_MIN <= 0, "non-conforming implementation");
return INT_MAX;
Getting integer operations right (i.e. if correctness matters)
If you're interested in safe integer arithmetic, have a look at my implementation of safe integer operations. If you want to see the patterns (rather than this lengthy text output) on which operations fail and which succeed, choose this demo.
Depending on the architecture, there may be other options to ensure correctness, such as gcc's option -ftrapv.
INT_MAX + INT_MIN < 0 ? INT_MAX : -INT_MIN
Edited to add explanation: Of course the difficulty is that -INT_MIN or abs(INT_MIN) will be undefined if -INT_MIN is too big to fit in an int. So we need some way of checking whether this is the case. The condition INT_MAX + INT_MIN < 0 tests whether -INT_MIN is greater than INT_MAX. If it is, then INT_MAX is the smaller of the two absolute values. If not, then INT_MAX is the larger of the two absolute values, and -INT_MIN is the correct answer.
The "conditional abs" you propose is not equivalent to std::abs (or fabs) for floating point numbers, see e.g.
#include <iostream>
#include <cmath>
int main () {
double d = -0.0;
double a = d < 0 ? -d : d;
std::cout << d << ' ' << a << ' ' << std::abs(d);
}
output:
-0 -0 0
Given -0.0 and 0.0 represent the same real number '0', this difference may or may not matter, depending on how the result is used. However, the abs function as specified by IEEE754 mandates the signbit of the result to be 0, which would forbid the result -0.0. I personally think anything used to calculate some "absolute value" should match this behavior.
For integers, both variants will be equivalent both in runtime and behavior. (Live example)
But as std::abs (or the fitting C equivalents) are known to be correct and easier to read, you should just always prefer those.
The first thing that comes to mind is readability.
Compare these two lines of code:
int x = something, y = something, z = something;
// Compare
int absall = (x > 0 ? x : -x) + (y > 0 ? y : -y) + (z > 0 ? z : -z);
int absall = abs(x) + abs(y) + abs(z);