6

How can I obtain the value of INT_MAX using only the bitwise operators, in C? I expected ~0 to be 1111111111 (complement of 1, so decimal -1) and ~0 >> 1 to be 0111111111, which would be max, but it's still -1.

Why is that and how can I obtain the value of INT_MAX by using bit operations?

Paul Manta
  • 30,618
  • 31
  • 128
  • 208

8 Answers8

10

Try ~0UL >> 1. The issue is that C will do a sign-extended right shift if it's dealing with a signed type. This is why you're still getting negative one -- because it's shifting in another 1 bit to match the 1 bit that was there. (That way -8 >> 1 gives -4 as you'd like for fast divisions by two.)

Kaganar
  • 6,540
  • 2
  • 26
  • 59
  • 5
    `~0UL >> 1` is LONG_MAX. You need `~0U >> 1`. Maybe also cast it to `int`, so it would have the right type. – ugoren Feb 22 '12 at 20:51
  • Subtle but good point -- uhg, compiler differences always get the best of me. Question is, is any of this ANSI or is there no real standard? – Kaganar Feb 22 '12 at 20:53
  • I think the standard says to use INT_MAX. Your solution works for 2's complement, i.e. any real cpu. As an alternative, I think `for(x=0;x+1>x;x++);` is quite robust, though slow. – ugoren Feb 22 '12 at 21:01
  • Thinking again, I think it is guaranteed to work. Unsigned numbers are well defined. Signed positive numbers must have the same encoding. The high bit must be the sign (1=negative). So this pattern necessarily gives the largest positive number. – ugoren Feb 22 '12 at 21:08
  • @ugoren That loop would work for unsigned numbers, but signed overflow is undefined behaviour. – Daniel Fischer Feb 22 '12 at 21:17
  • @DanielFischer, The loop indeed has UB. In practice, it won't crash, so it will stop on INT_MAX (because x+1 surely isn't larger). But it's worthless in practice, and not robust in theory, which doesn't leave much. – ugoren Feb 22 '12 at 21:21
  • @DanielFischer, There's no right-shifting of negative signed values here. `~0U` is unsigned. – ugoren Feb 22 '12 at 21:23
  • @ugoren, no the high bit must not necessarily the sign, unfortunately the standard allows scenarios that are more complicated. So this solution doesn't work. There is no completely portable way to find that value but to use `INT_MAX`. That is why this kind of macros exist for all integer types. – Jens Gustedt Feb 22 '12 at 21:24
  • @ugoren a compiler can assume `x + 1 > x` is always `1` if `x` is an `int` because of the overflow. Actually I remember `gcc` would do this optimization when all optimizations are enabled. – ouah Feb 22 '12 at 21:26
  • @ugoren My first comment referred to "The issue is that C will do a sign-extended right shift if it's dealing with a signed type." in the answer. Practically, I know of no implementation behaving differently, but the standard leaves it up to the implementation. As for the loop, what ouah said. – Daniel Fischer Feb 22 '12 at 21:36
  • @DanielFischer implementations on small microcontrollers with logical right shift instructions but not arithmetic right shift usually don't propagate the sign. – ouah Feb 22 '12 at 21:40
  • @JensGustedt, I actually based my comment on the c99 standard, which clearly defines the meaning of the sign bit. Regarding ANSI C, I'm really not sure - I find it harder to read. – ugoren Feb 22 '12 at 21:41
  • @ouah, I guess you're right here. I almost said that the compiler won't be stupid enough to reduce it to `while(1);`, but I've seen worse. You could prevent it by calling a function that returns `x+1`, and is defined in another file. But it's really going too far. – ugoren Feb 22 '12 at 21:50
  • @ugoren, no, even C99 only defines the meaning of the sign bit, but not the relative position in the corresponding unsigned type. Please have a look at http://gustedt.wordpress.com/2010/09/21/anatomy-of-integer-types-in-c/ – Jens Gustedt Feb 22 '12 at 22:01
  • @ouah Ah, thanks. I guess those would be freestanding implementations? I'd be somewhat surprised to learn of a hosted implementation not using sign-extension. – Daniel Fischer Feb 22 '12 at 22:03
2

If you shift a negative number to the right, the new bits of the number may be 1 (to keep it negative). That why you get -1.

Edit: You can do something like:

int i=1;
while (i<<1) i<<=1;
i=~i;
asaelr
  • 5,438
  • 1
  • 16
  • 22
  • "May be"? As in, not in all implementations? – Paul Manta Feb 22 '12 at 20:30
  • 1
    I think that the standard says that it depends on the implementation. – asaelr Feb 22 '12 at 20:32
  • @PaulManta Right-shifting negative numbers is implementation-defined indeed (6.5.7(5)). asaelr, but for `E1 > 0` a value of a signed type, `E1 << E2` is undefined behaviour if `E1 * 2^E2` is not representable in that type, so your alternative relies on a specific interpretation of this undefined behaviour. – Daniel Fischer Feb 22 '12 at 21:23
2

If you treat 0 as an unsigned integer, the compiler will not perform a signed shift:

int i = ~0U >> 1;

This will give you INT_MAX

ardnew
  • 2,028
  • 20
  • 29
1

(1<<31)-1)

as well. This is an old thread but i'll post it anyway for anyone googling it. But it's not entirely bitwise, and it's assuming an "int" on your machine is 32bit.

catfood
  • 439
  • 5
  • 5
1

As far as I know, there is no portable solution except to use the INT_MAX macro. See my longstanding question:

Programmatically determining max value of a signed integer type

and the question it's based on:

C question: off_t (and other signed integer types) minimum and maximum values

Community
  • 1
  • 1
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0
#include <stdio.h>

int main(){
    int max = ~0U >> 1;
    int min = ~max;

    printf("Max = 0x%X, min = 0x%X", max, min);
    return 0;
}

Output:

Max = 0x7FFFFFFF, min = 0x80000000
kaushal
  • 785
  • 12
  • 27
0

Here's how you can find MIN/MAX of any signed integer type. However, I assume left shift does arithmetic shift and fills blanks with zeros, which is true for majority of compilers.

#define MIN_OF_SIGNED_TYPE(type) ((type)1 << (sizeof(type) * 8 - 1))
#define MAX_OF_SIGNED_TYPE(type) (~MIN_OF_SIGNED_TYPE(type))

#define MY_INT_MIN MIN_OF_SIGNED_TYPE(int)
#define MY_INT_MAX MAX_OF_SIGNED_TYPE(int)
ilnar_al
  • 932
  • 9
  • 13
-1
int int_max = (unsigned int)-1 >> 1;
Mukesh Bharsakle
  • 403
  • 1
  • 4
  • 17