Absolute value of INT_MIN
Solution 1
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
Solution 2
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 );
Solution 3
There is no portable way to extract the absolute value of the most negative number as an integer. The ISO C standard says (§6.2.6.2¶2):
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 ).
Notice it uses ≤, not <.
Since the sign bit in 2's complement has the value −(2M), and each value bit has a value that is a power of two between 1 and 2M-1, there is no way an unsigned integer on implementations where M=N can represent 2N, it can only represent up to 2N-1 = 1+2+...+2N-1.
Comments
-
Morgan Wilde almost 2 years
How could I extract the absolute value of
INT_MIN
without overflowing? See this code for the problem:#include <limits.h> #include <stdio.h> #include <stdlib.h> int main(void) { printf("INT_MAX: %d\n", INT_MAX); printf("INT_MIN: %d\n", INT_MIN); printf("abs(INT_MIN): %d\n", abs(INT_MIN)); return 0; }
Spits out the following
INT_MAX: 2147483647 INT_MIN: -2147483648 abs(INT_MIN): -2147483648
I need this for a check if an
int
value is greater than zero.As for this question being a duplicate of Why the absolute value of the max negative integer -2147483648 is still -2147483648?, I have to disagree, since this is a HOW, not a WHY question.
-
Oliver Charlesworth over 10 yearsThat assumes that sizeof(long) > sizeof(int), which isn't always the case...
-
Morgan Wilde over 10 yearsI had a similar idea, but what happens when I need the
abs()
ofLONG LONG
? -
abligh over 10 years@OliCharlesworth: In which case use
long long int
(edited to fix this). -
Morgan Wilde over 10 years@abligh ok, this works on some level, so I'll upvote, but this isn't a full-proof solution.
-
abligh over 10 years@MorganWilde no 2's complement signed integer type is going to be able to represent the the absolute value of the largest negative type.
-
Oliver Charlesworth over 10 years
( INT_MIN > 0 ) ? INT_MIN : -INT_MIN
- huh? -
Junior Dussouillez over 10 years"you have to include math.h to properly use abs". abs is in stdlib.h...
-
Morgan Wilde over 10 yearsThat's exactly what I meant when I said it isn't a full solution.
-
Utkan Gezer over 10 years@OliCharlesworth Whatever man, whatever... This is the exact translation; but of course, it will always be just
-INT_MIN
-
Utkan Gezer over 10 years@JuniorDussouillez I didn't say that it isn't in
stdlib.h
, did I? It is just in both. -
Morgan Wilde over 10 yearsNice, it seems so obvious now. Thanks!
-
Oliver Charlesworth over 10 years@ThoAppelsin: Indeed, but
-INT_MIN == INT_MIN
in practice (although technically undefined behaviour). -
Brandin over 10 yearsIs this actually correct or does it happen to work due to implementation-defined behaviour
-
Oliver Charlesworth over 10 yearsNote this still invokes UB; from the C99 standard for
abs
: "if the result cannot be represented, the behaviour is undefined." -
abligh over 10 years@MorganWilde: What I'm saying is that provably you cannot have a full solution. Let's say the platform has no integer type longer than 32 bits, and you are using the longest type (and trying to find the absolute value of the smallest integer). Then
abs(INT_MIN)
will be2147483648
, but that will be one larger than theINT_MAX
which is by definition the largest integer that the largest 2's complement type (by assumption) can help. -
xmoex over 10 yearsactually: for this you don't need to call abs(INT_MIN) anymore, as just INT_MIN will cause the same result. As found in various locations e.g. like acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#abs calling abs on INT_MIN causes undefined behaviour!
-
ajay over 10 years@OliCharlesworth the man page of
abs
says -Returns the absolute value of the integer argument, of the appropriate integer type for the function.
Doesn't it mean that return value ofabs
will always fit inunsigned int
type. -
Oliver Charlesworth over 10 years@ajay: Alas no; the return type of
abs
isint
. -
Morgan Wilde over 10 years@OliCharlesworth I wrote my own
absu
that returnsunsigned int
and thus this answer solves my problem. -
Oliver Charlesworth over 10 years@MorganWilde: Ok, but then the definition of that function is the real answer; you should post it! (The code in this answer gives UB, so I have to downvote it...)
-
xmoex over 10 yearscplusplus.com/reference/climits says that the actual values of those limits are implementation-dependent. so this solution works only if INT_MIN is not equal to LONG_MIN
-
Morgan Wilde over 10 years@OliCharlesworth I've included my function in this answer, I think it should be sufficient.
-
Oliver Charlesworth over 10 years@MorganWilde: Alas, that still exhibits UB.
-value
is still of typeint
, and thus overflows forINT_MIN
. -
Brandin over 10 yearsWouldn't a simpler solution be just to convert the value of INT_MIN into a string representation and then take off the minus sign
-
xmoex over 10 years@MorganWilde: when using your absu function you can get comparison problems when using it with a signed integer. found: stackoverflow.com/a/5416498/944201
-
ninjalj over 10 years@OliCharlesworth: that would be only for 2's complement. The standard allows signed magnitude and 1's complement, which I suspect are still used on some DSPs.
-
Morgan Wilde over 10 years@xmoex would typecasting values before comparing be enough to solve this one?
-
xuefu over 10 yearsyeah, thanks for your remind.
-
ninjalj over 10 years@MorganWilde: typecasting before comparing wouldn't be enough. But I suspect typecasting to unsigned the third operand of the conditional expression instead of negating it may be legal. Forget that, I'm not sure unsigned types are required to have more value types than their corresponding signed type.
-
xmoex over 10 yearsif possible (and necessary) i'd cast both values needed for comparison to the next greater signed variant of integer typ like long int (or long long int if int and long is the same size on your machine). this way you occupy more memory but your solution is more generic as you can use one of the provided abs functions for long int or long long int without messing around with lower quality hack-arounds and you'd do a real comparison of two signed values... you could check my answer below if you like.
-
Morgan Wilde over 10 years@ninjalj here we go! This seems like the perfect solution.
-
ninjalj over 10 years@MorganWilde: Unfortunately, unsigned types may have a padding bit that corresponds to the sign bit of the signed type. So, the value may be not representable as unsigned.
-
Brandin over 10 years@MorganWilde I dont see the solution because as it stands you have described three different problems (displaying the absolute value of INT_MIN, storing the absolute value of INT_MIN in an
unsigned
(impossible) and comparing values involving INT_MIN). Choose a problem first and focus on that. -
Brandin over 10 yearsEveryone commenting here needs to go to the very top and read this comment:
The absolute value of the smallest number in two-complement just does not exist.
from deviantfan. Trying to cast INT_MIN into unsigned just isnt representable. As in that comment you need to describe what youre actually trying to accomplish here -
Morgan Wilde over 10 years@Brandin OK, great comment, I'll go back to the drawing board and try to distill the issue. Thanks for the effort.
-
ajay over 10 yearsSo using
unsigned int
only lets me represent one more value2^(N-1)
? This is confusing. Isn't the range ofunsigned int
0
to2^(N) - 1
? The standard also says(6.2.5:9) -The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type
. So the difference in the the two ranges is only one value2^(N-1)
? -
ninjalj over 10 yearsUsing unsigned doesn't guarantee you any more values. But, you can check the macros in
limits.h
INT_MAX
,UINT_MAX
, ... to see if your particular platform gives you an strictly larger value range of non-negative integers for unsigned integers than it does for signed integers. -
ajay over 10 years
UINT_MAX
is2^32 - 1
andINT_MAX
is2^31 - 1
on my machine. I wonder why is it not guaranteed and then what is the use of using unsigned types anyway? Also supposing thatsigned
andunsigned
have the same range (except2^(N-1)
), what value would the signed type with sign bit1
represent in the unsigned type? -
ninjalj over 10 yearsIntegers can have padding bits. Some integer values may be trap representations (similar to NaNs in floating point numbers). Older machines from the 60s and 70s, and DSPs do some weird things. The C standard is written so as to support every quirky machine ever known to have run C.
-
ajay over 10 yearsThe standard says nothing about how many padding bits are there. It also says there need not be any padding bits. Is there any way I can find out if there's one on my machine? This is really quirky and I never knew this. Trying to write
C
that runs on all machines that ever usedC
is really tough then! -
ninjalj over 10 yearsYou could probably tell if a platform has padding bits with
sizeof
andCHAR_BIT
. I don't know of any modern platform that has, but probably some DSPs do. -
chux - Reinstate Monica over 10 years@Brandin If
|int|
will fit into anunsigned
, suggestunsigned absu(int value) { return (value < 0) ? ((unsigned)(-1 - value) + 1u : (unsigned)value; }
to avoid UB. -
Brandin over 10 years@chux Your comment seems clever but I stopped reading right after
If |int| will fit into an unsigned
(as mentioned it wont in 2s complement) -
supercat over 5 years@Brandin: While the Standard would allow an implementation to use two's-complement format for signed types, and have an extra padding bits in unsigned, I really doubt that any do. Otherwise, the extra bit in an unsigned type would allow it to accommodate values up to
2*INT_MAX+1
, which is more than enough range to handle|-INT_MIN|
. -
supercat over 5 years@chux: As a simplification,
(value < 0) ? -(unsigned)value : (unsigned)value
. Casting to the unsigned type before the negation would result in fully-defined behavior with the only possible anomaly occurring on a machine where e.g.int
is 17 bits two's-complement with asymmetric range andunsigned
is 16 bits + 1 padding. On such machines,INT_MIN
would be -65536, butUINT_MAX
would only be 65535. The behavior of convertingINT_MIN
tounsigned
would be defined as yielding 0u, and -0u is of course 0u. -
chux - Reinstate Monica over 5 years
-
chux - Reinstate Monica over 5 years@supercat The case where
signed_type_MAX == unsigned_type_MAX
and notsigned_type_MAX == unsigned_type_MAX/2
I have encounter once, pre-C99 on a platform with a 64-bit signed *,/,+,-, opcodes but not unsigned counterparts. There existed a wide integer pair types as 64-bit 2's complement and (63-bit unsigned + 1 pad). AFAIK, it was C compliant - at the time. I could imagine a like-wise case today with n==128. -
supercat over 5 years@chux: I would not find it surprising for sign-magnitude or ones'-complement implementations to treat unsigned types as signed with the sign bit forced to zero, but it would seem weird for a two's-complement platform to do so. Was the system you were talking about two's-complement?
-
chux - Reinstate Monica over 5 yearsYes. ......... iirc