Exercise 2.1 - Count the Ranges#

Question#

Write a program to determine the ranges of char, short, int, and long variables, both signed and unsigned, by printing appropriate values from standard headers and by direct computation. Harder if you compute them: determine the ranges of the various floating-point types.

/***
 *
 * Exercise 2.1
 *
 * Program to print maximum, minimum limits of char, int, long using
 * calculation
 *
 ***/

/* The logic used is
* ~0 will give bits in 1s.
* (unsigned <type>) will cast it unsigned.
* >> 1 right shifts 1 bit to remove the sign bit.
* (<type>) casting it the required type again
*/

#include<stdio.h>
#include<limits.h>
#include<float.h>

int main(void)
{
    /* ranges of various floating-point types through calculation */
    printf("Ranges of various floating-point types through calculation:\n");
    
    printf("Minimum Signed Char %d\n",-(char)((unsigned char) ~0 >> 1) - 1);
    printf("Maximum Signed Char %d\n",(char) ((unsigned char) ~0 >> 1));

    printf("Minimum Signed Short %d\n",-(short)((unsigned short)~0 >>1) -1);
    printf("Maximum Signed Short %d\n",(short)((unsigned short)~0 >> 1));

    printf("Minimum Signed Int %d\n",-(int)((unsigned int)~0 >> 1) -1);
    printf("Maximum Signed Int %d\n",(int)((unsigned int)~0 >> 1));

    printf("Minimum Signed Long %ld\n",-(long)((unsigned long)~0 >>1) -1);
    printf("Maximum signed Long %ld\n",(long)((unsigned long)~0 >> 1));

    /* Unsigned Maximum Values */

    printf("Maximum Unsigned Char %d\n",(unsigned char)~0);
    printf("Maximum Unsigned Short %d\n",(unsigned short)~0);
    printf("Maximum Unsigned Int %u\n",(unsigned int)~0);
    printf("Maximum Unsigned Long %lu\n\n",(unsigned long)~0);
    
    /* ranges of various floating-point types from standard headers */
    printf("Ranges of various floating-point types from standard headers:\n");
    
    printf("Minimum Signed Char %d\n", SCHAR_MIN);
        printf("Maximum Signed Char %d\n", SCHAR_MAX);
    
        printf("Minimum Signed Short %d\n", SHRT_MIN);
        printf("Maximum Signed Short %d\n", SHRT_MAX);
    
        printf("Minimum Signed Int %d\n", INT_MIN);
        printf("Maximum Signed Int %d\n", INT_MAX);
    
        printf("Minimum Signed Long %ld\n", LONG_MIN);
        printf("Maximum signed Long %ld\n", LONG_MAX);
    
        /* Unsigned Maximum Values */
    
        printf("Maximum Unsigned Char %d\n", UCHAR_MAX);
        printf("Maximum Unsigned Short %d\n", USHRT_MAX);
        printf("Maximum Unsigned Int %u\n", UINT_MAX);
        printf("Maximum Unsigned Long %lu\n", ULONG_MAX);
        
    return 0;
}

Explanation#

The execution of the above program will give:

Minimum Signed Char -128
Maximum Signed Char 127
Minimum Signed Short -32768
Maximum Signed Short 32767
Minimum Signed Int -2147483648
Maximum Signed Int 2147483647
Minimum Signed Long -2147483648
Maximum signed Long 2147483647
Maximum Unsigned Char 255
Maximum Unsigned Short 65535
Maximum Unsigned Int 4294967295
Maximum Unsigned Long 4294967295

In order explain how we calculate the maximum values, we will have to do some bit arthimetic. Let’s start by calculating the maximum unsigned char.

Sign bit is usually the left most bit of the type. To make it unsigned, we remove the sign bit and store 0 in it’s place.

To represent (unsigned char) 0 = 0000 0000 To represent it’s complement, (unsigned char) ~0 = 1111 1111

Right Shift 1 will shift that entire sequence to the right and insert 0 from the left side, so it will give 0111 1111

Converting 0111 1111 to integer will be:

0 * 2^7 + 1 * 2^ 6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 *2^2 + 1 * 2^1 + 1 * 2^0
= 0 * 0 + 1 * 64 + 1 * 32 + 1 * 16 + 1 * 8 + 1 * 4 + 1 * 2 + 1 * 1
= 0 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 127

That is the maximum signed char value. To get the minimum signed char value, we look for the number in the other end of the number line.

That is got by, multiplying it by -1 and going one number further to the left in the number line:

= - 127 -1
= -128

So our range is displayed like this:

-128..-2..-1..0 1 2 3 4... 127

Maximum signed short#

To get the maximum signed short number, we start with unsigned short type again and repeat the same operations like we did above.

(short)((unsigned short)~0 >> 1)

In our compiler, a short is 2 bytes

(unsigned short) 0 means 0000 0000 0000 0000 (unsigned short) ~0 means 1111 1111 1111 1111

Logical right shift, is we are eliminating the sign bit, which is the left most bit in the sequence.

(unsigned short)~0 >> 1)

Take this portion 1111 1111 1111 111 1 and place it as 1111 1111 1111 111 And then add 0 to the left 0 1111 1111 1111 111 Rearranging we get 0111 1111 1111 1111

What is value of 0111 1111 1111 1111 ?

Similar to above:

=   0 * 2^15 + 1 * 2^14 + 1 * 2^13 + 1 * 2^12
    + 1 * 2^11 + 1* 2^10 + 1 * 2^9 + 1 * 2^8
    + 1*2^7 + 1 * 2^6 + 1*2^5 + 1*2^4
    + 1* 2^3 + 1*2^2 + 1* 2^1 +1*2^0

    = 16384 + 8192 + 4096 + 2048 + 1024 + 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2
    = + 1 32767

So, our maximum unsigned short is 32767

Mininum unsigned short will be the negative of that number going one step further, i.e:

= -32767 - 1 = -32768

Similarily, we can calculate for int and long types.

For unsigned types, we do not do the shifting (to remove the sign) but simply print the value of all 1s of the type

(unsigned char)~0;

can be represented as (unsigned char) ~0 = 1111 1111

= 1 * 2^7 + 1 * 2^ 6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 *2^2 + 1 * 2^1 + 1 * 2^0
= 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 255