C find maximum two's complement integer

-2

I am tasked with finding maximum two's complement integer, or the TMax. I am at a complete loss for how to do this. I know that the correct value is 0x7fffffff, or 2147483647, but I do not know how exactly to get to this result. That's the maximum number for a 32 bit integer. I cannot use functions or conditionals, and at most I can use 4 operations. Can anyone try and help explain this to me? I know the way to find the maximum number for a certain bit count is 2^(bits - 1) - 1, so 2^(31) - 1 = 2147483647

c
binary
twos-complement
asked on Stack Overflow Oct 17, 2018 by Sam Tyson

4 Answers

1

Assuming you know that your machine uses two's complement representation, this is how you would do so in a standard compliant manner:

unsigned int x = ~0u;
x >>= 1;
printf("max int = %d\n", (int)x);

By using an unsigned int, you prevent any implementation defined behavior caused by right shifting a negative value.

answered on Stack Overflow Oct 17, 2018 by dbush • edited Oct 17, 2018 by Eric Postpischil
1

find maximum two's complement integer

int TMax = -1u >> 1 or -1u/2 is sufficient when INT_MAX == UINT_MAX/2 to find the maximum int,

This "works" even if int is encoded as 2's complement or the now rare 1s complement or sign magnitude.


Better to use

#include <limits.h>
int TMax = INT_MAX;

Other tricks can involve undefined, implementation defined, unspecified behavior which are best avoided in C.

answered on Stack Overflow Oct 17, 2018 by chux - Reinstate Monica • edited Oct 17, 2018 by chux - Reinstate Monica
1

There are two scenarios in which you may be looking for the maximum positive number, either given an integer data type or given a number of bits. The are also two solutions.

Fill and shift right

Working in an integer data type of a size that exactly matches the size of the desired twos complement data type, you might be able to solve the problem by

(unsigned 'type') ^0)>>1 

or equivalently,

(unsigned 'type') ^0)/2.

For example, on a machine where short is 16 bits,

(unsigned short) ^0   ==>  0xFFFF  (65535)
((unsigned short) ^0 ) >> 1  ==>  0x7FFF  (32767)

On a 32 bit data type, this method gives us 0x7FFFFFFF (2147483647).

In C, an integer type has a minimum size only, c.f. an int can be 16 bits, 32 bits, or larger. But, the word size used in the calculation must exactly match that of the intended target.

Also, note that the data must be an unsigned type. The right shift for a signed type is usually implemented as a sign extended shift (the sign bit is copied into the result).

Set the sign bit only and subtract 1

The second technique, which works for any word size equal to or larger than the number of bits of the desired twos complement word size, is

(unsigned integer_type) 1<<(n-1)-1

For example, in any integer word size greater to or larger than 16, we can find the TMAX for 16 as

(unsigned integer_type) 1<<15  ==>  binary 1000 0000 0000 0000  (0x8000)
(unsigned integer_type) (1<<15 - 1) == > 0111 1111 1111 1111 (0x7FFF)

This is robust and works on almost any scenario that provides adequate word size.

Again the data type for the calculation has to be unsigned if the word size in the calculation is that of the target. This is not necessary for a larger word size.

Examples

In the first example, we show that the second method works for 32 bits, using long or long long types.

#include <stdio.h>

int main() {

  printf( "%ld\n", (long) ( ( ((unsigned long) 1)<<31 ) - 1 ) );
  printf( "%lld\n", (long long) ( ( ((unsigned long long) 1)<<31 ) - 1 ) );

}

Output:

2147483647
2147483647

And here we show that the first method, shift right from all bits set, fails when int is not exactly 32 bits, which as noted, is not guaranteed in C.

#include <stdio.h>

int main() {

  printf( "from long long %lld  (%zu bits)\n", ( (unsigned long long) ~0 )>>1,
      sizeof(unsigned long long)*8 );

  printf( "from long %ld  (%zu bits)\n",  ( (unsigned long) ~0 )>>1,
      sizeof(unsigned long)*8  );

  printf( "from int %d  (%zu bits)\n",  ( (unsigned int) ~0 )>>1,
      sizeof(unsigned int)*8  );

  printf( "from short %d  (%zu bits)\n",  ( (unsigned short) ~0 )>>1,
      sizeof(unsigned short)*8  );
}

Output:

from long long 9223372036854775807  (64 bits)
from long 9223372036854775807  (64 bits)
from int 2147483647  (32 bits)
from short 32767  (16 bits)

Again, recall that the C language only guarantees a minimum size for any integer data types. An int can be 16 bits or 32 bits or larger, depending on your platform.

answered on Stack Overflow Oct 17, 2018 by DrM • edited Oct 25, 2018 by DrM
0

Thanks for the help, everyone! Turns out I cannot use macros, unsigned, or longs. I came to this solution:

~(1 << 31)

That generates the correct output, so I will leave it at that!

answered on Stack Overflow Oct 18, 2018 by Sam Tyson • edited Oct 18, 2018 by Sam Tyson

User contributions licensed under CC BY-SA 3.0