/* C compiles every comparison between two integer types; it converts both
   sides to one common type first, and that conversion decides the answer.
   Small types are promoted to int, where every value keeps its sign. An int
   that meets an unsigned int is converted to unsigned, and -1 becomes the
   largest unsigned int there is. The two fixes at the end compare in a type
   that holds both ranges, or look at the sign before converting. */
#include <float.h>
#include <limits.h>
#include <stdio.h>

/* Some answers below lean on type widths, which C leaves to the platform. These
   lines make them promises: a machine where one fails will not build this. */
_Static_assert(USHRT_MAX <= INT_MAX, "int holds every unsigned short");
_Static_assert(UINT_MAX <= LLONG_MAX, "long long holds every unsigned int");
_Static_assert(UINT_MAX == 4294967295u, "unsigned int is 32 bits");
_Static_assert(CHAR_BIT == 8, "a char is 8 bits");
_Static_assert(DBL_MANT_DIG == 53, "a double has 53 significant bits");

int main(void)
{
    /* Integer promotion: an unsigned short fits in an int, so both sides
       become int and the comparison is the one you meant. */
    int ten = 10;
    unsigned short hundred = 100;
    short minus_one_short = -1;
    unsigned short one_short = 1;
    printf("int 10 < unsigned short 100        -> %d\n", ten < hundred);
    printf("short -1 < unsigned short 1        -> %d\n", minus_one_short < one_short);

    /* The usual arithmetic conversions: int and unsigned int have the same
       rank, so the unsigned type wins and -1 is converted to it. */
    int minus_one = -1;
    unsigned int one = 1;
    printf("int -1 < unsigned int 1            -> %d\n", minus_one < one);
    printf("  because (unsigned int)-1         =  %u\n", (unsigned int)minus_one);
    printf("  which is UINT_MAX                =  %u\n", UINT_MAX);
    printf("-1L < 1UL                          -> %d\n", -1L < 1UL);

    /* The same rules for an integer against a double: the integer converts,
       and 2^53 + 1 has no double of its own, so it lands on its neighbour's. */
    long long two_53_plus_1 = 9007199254740993LL;
    printf("2^53 + 1 == (double)(2^53 + 1)     -> %d\n",
           two_53_plus_1 == (double)two_53_plus_1);

    /* Converting to an unsigned type is defined for every value: it wraps
       modulo 2^N. 300 - 256 = 44. */
    int three_hundred = 300;
    printf("(unsigned char)300                 -> %d\n", (unsigned char)three_hundred);

    /* Fix one: convert both sides to a type that holds both ranges. */
    printf("(long long)-1 < (long long)1u      -> %d\n",
           (long long)minus_one < (long long)one);

    /* Fix two: a negative int is below every unsigned value, so say so
       before the conversion gets a chance to change it. */
    printf("-1 < 0 || (unsigned int)-1 < 1u    -> %d\n",
           minus_one < 0 || (unsigned int)minus_one < one);
    return 0;
}
