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 Overflow
🌐
Cppreference
en.cppreference.com › w › cpp › numeric › math › abs
std::abs, std::labs, std::llabs, std::imaxabs - cppreference.com
March 14, 2025 - #include <climits> #include <cstdlib> #include <iostream> int main() { std::cout << std::showpos << "abs(+3) = " << std::abs(3) << '\n' << "abs(-3) = " << std::abs(-3) << '\n'; // std::cout << std::abs(INT_MIN); // undefined behavior on 2's complement systems }
Top answer
1 of 8
124

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.

2 of 8
51

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 to long before. We, however, must either

    • cast them back into ints, which does not work because Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).
    • Or continue with longs somehow hoping that we'll never call Math.abs(long) with a value equal to Long.MIN_VALUE, since we also have Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
  • We can use BigIntegers everywhere, because BigInteger.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 from Integer.MAX_VALUE to 0 instead of Integer.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.

🌐
Cppreference
en.cppreference.com › w › c › numeric › math › abs
abs, labs, llabs, imaxabs - cppreference.com
May 25, 2024 - #include <limits.h> #include <stdio.h> #include <stdlib.h> int main(void) { printf("abs(+3) = %d\n", abs(+3)); printf("abs(-3) = %d\n", abs(-3)); // printf("%+d\n", abs(INT_MIN)); // undefined behavior on 2's complement systems }
🌐
Cplusplus
cplusplus.com › reference › cstdlib › abs
abs
No-throw guarantee: this function throws no exceptions. If the result cannot be represented by the returned type (such as abs(INT_MIN) in an implementation with two's complement signed values), it causes undefined behavior.
🌐
GitHub
github.com › gpuweb › gpuweb › issues › 3785
abs(INT_MIN) should be well-defined on integral types · Issue #3785 · gpuweb/gpuweb
January 27, 2023 - Historically we've generally had different policies for integer operations vs floating point operations. We should make abs(INT_MIN) well-defined on integral types.
🌐
Code Yarns
codeyarns.com › tech › 2012-02-14-c-abs-and-its-quirk-with-int_min.html
Code Yarns – C++: abs() and its quirk with INT_MIN
Though the number of values that ... range. Coming back to abs(), since its return type is the same as the input type it simply cannot represent the positive value (-INT_MIN) in an int....
🌐
Coderanch
coderanch.com › t › 231198 › certification › Math-abs-Integer-MIN-return
Math.abs(Integer.MIN_VALUE) return a negative vaue,why? (OCPJP forum at Coderanch)
According to the API, abs() checks to see if the value is positive. If so it returns the number, if not, it returns -1 * the number. Getting into the bits, -1 * Integer.MIN_VALUE = Integer.MIN_VALUE. Here's why...(I'll use only four bits to keep it simple) -1 in binary (with two's complement ...
Find elsewhere
🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › c-runtime-library › reference › abs-labs-llabs-abs64
abs, labs, llabs, _abs64 | Microsoft Learn
October 26, 2022 - If the absolute value of the argument can't be represented by the return type, the abs functions return the argument value unchanged. Specifically, abs(INT_MIN) returns INT_MIN, labs(LONG_MIN) returns LONG_MIN, llabs(LLONG_MIN) returns LLONG_MIN, ...
🌐
GNU
gnu.org › software › libc › manual › html_node › Absolute-Value.html
Absolute Value (The GNU C Library)
Most computers use a two’s complement integer representation, in which the absolute value of INT_MIN (the smallest possible int) cannot be represented; thus, abs (INT_MIN) is not defined.
🌐
Embarcadero
docwiki.embarcadero.com › RADStudio › Sydney › en › Abs
abs - RAD Studio
The abs function returns an integer in the range of 0 to INT_MAX, with the exception that an argument with the value INT_MIN is returned as INT_MIN.
🌐
The Open Group
pubs.opengroup.org › onlinepubs › 009695399 › functions › abs.html
abs
In two's-complement representation, the absolute value of the negative integer with largest magnitude {INT_MIN} might not be representable.
🌐
Scaler
scaler.com › home › topics › abs() in c++
abs() in C++ | abs() Function in C++ - Scaler Topics
October 10, 2025 - For Example: abs is called on INT_MIN = -2147483648. The range of int in C++ is from -2147483648 to 2147483647. So if abs(-2147483648) is called, it will do (-1)*(-2147483648), which will result in it being out of range of int.
🌐
IBM
ibm.com › support › pages › apar › IJ24659
IJ24659: OPTIMIZATION MOVING ABS() CALL CAUSING INCORRECT VALUE WITH INT_MIN
A code sequence that looks like: int num_base=10 ; ... int sub = value / num_base; int mod = value % num_base; sub = abs(sub); The input value for 'value' is INT_MIN, i.e. -2147483648. The division "value / num_base" should always make this larger, i.e. closer to 0, i.e.
Top answer
1 of 6
23

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.

2 of 6
9
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.

🌐
GeeksforGeeks
geeksforgeeks.org › c++ › int_max-int_min-cc-applications
INT_MAX and INT_MIN in C/C++ and Applications - GeeksforGeeks
May 13, 2025 - INT_MIN = -2147483648 = 10000000000000000000000000000000 · Here 1st bit represents the sign bit which is set to one meaning it is a negative number and the next part is a 31-bit binary representation for 2147483648. Now if we try to take the absolute value of INT_MIN it will try to give us +2147483648 and this value can't be represented in the Integer form as the maximum value that can be represented is +2147483647 as on the positive side we have to represent 231 integers but 0 is also included so the range from 1 to 2147483648 changes to 0 to 2147483647 and for this reason the abs(INT_MIN) can't be represented in this range and the answer returned is same as INT_MIN.