Hello all,
In K&R2 one exercise asks the reader to compute and print the limits for
the basic integer types. This is trivial for unsigned types. But is it
possible for signed types without invoking undefined behaviour
triggered by overflow? Remember that the constants in limits.h cannot
be used.
/*
The standard hearder <limits.h> was introduced on the same page (36)
as the exercise.
We are told to compute the values by standard headers and by direct
computation.
We are also told to determine the ranges of the various floating point
types.
The only hard part I see is the signed integer min and max values
without using <limits.h> because I do not see how you can do it
portably. We can probably deduce the hardware type, but I am not sure
about what guarantees we have as to internal representation. I guess
also we will need separate routines for 2's complement, 1's
complement, sign magnitude, and whatever other types are allowed (e.g.
is decimal storage allowed? I know of CPUs that had BCD instructions
in hardware).
Anyway, here are all the trivial answers:
*/
#include <stdio.h>
#include <limits.h>
#include <float.h>
void floating_limits(void)
{
puts("\nFloating point limits:");
printf("DBL_DIG %u\n", (unsigned) DBL_DIG);
printf("DBL_EPSILON %*.*g\n", DBL_DIG + 3, DBL_DIG,
DBL_EPSILON);
printf("DBL_MANT_DIG %u\n", (unsigned) DBL_MANT_DIG);
printf("DBL_MAX %*.*g\n", DBL_DIG + 3, DBL_DIG, DBL_MAX);
printf("DBL_MAX_10_EXP %u\n", (unsigned) DBL_MAX_10_EXP);
printf("DBL_MAX_EXP %u\n", (unsigned) DBL_MAX_EXP);
printf("DBL_MIN %*.*g\n", DBL_DIG + 3, DBL_DIG, DBL_MIN);
printf("DBL_MIN_10_EXP %d\n", DBL_MIN_10_EXP);
printf("DBL_MIN_EXP %d\n", DBL_MIN_EXP);
#ifdef DBL_RADIX
printf("DBL_RADIX %u\n", (unsigned) DBL_RADIX);
#endif
#ifdef DBL_ROUNDS
printf("DBL_ROUNDS %u\n", (unsigned) DBL_ROUNDS);
#endif
printf("FLT_DIG %u\n", (unsigned) FLT_DIG);
printf("FLT_EPSILON %*.*g\n", FLT_DIG + 3, FLT_DIG,
FLT_EPSILON);
#ifdef FLT_GUARD
printf("FLT_GUARD %u\n", (unsigned) FLT_GUARD);
#endif
printf("FLT_MANT_DIG %u\n", (unsigned) FLT_MANT_DIG);
printf("FLT_MAX %*.*g\n", FLT_DIG + 3, FLT_DIG, FLT_MAX);
printf("FLT_MAX_10_EXP %u\n", (unsigned) FLT_MAX_10_EXP);
printf("FLT_MAX_EXP %u\n", (unsigned) FLT_MAX_EXP);
printf("FLT_MIN %*.*g\n", FLT_DIG + 3, FLT_DIG, FLT_MIN);
printf("FLT_MIN_10_EXP %d\n", FLT_MIN_10_EXP);
printf("FLT_MIN_EXP %d\n", FLT_MIN_EXP);
printf("LDBL_DIG %u\n", (unsigned) LDBL_DIG);
printf("LDBL_EPSILON %*.*Lg\n", LDBL_DIG + 3, LDBL_DIG, (long
double) LDBL_EPSILON);
printf("LDBL_MANT_DIG %u\n", (unsigned) LDBL_MANT_DIG);
printf("LDBL_MAX %*.*Lg\n", LDBL_DIG + 3, LDBL_DIG, (long
double) LDBL_MAX);
printf("LDBL_MAX_10_EXP %u\n", (unsigned) LDBL_MAX_10_EXP);
printf("LDBL_MAX_EXP %u\n", (unsigned) LDBL_MAX_EXP);
printf("LDBL_MIN %*.*Lg\n", LDBL_DIG + 3, LDBL_DIG, (long
double) LDBL_MIN);
printf("LDBL_MIN_10_EXP %d\n", LDBL_MIN_10_EXP);
printf("LDBL_MIN_EXP %d\n", LDBL_MIN_EXP);
#ifdef LDBL_RADIX
printf("LDBL_RADIX %u\n", (unsigned) LDBL_RADIX);
#endif
#ifdef LDBL_ROUNDS
printf("LDBL_ROUNDS %u\n", (unsigned) LDBL_ROUNDS);
#endif
}
void signed_limits_guarantee(void)
{
static const short shrt_min_est = -32767;
static const short shrt_max_est = +32767;
static const int int_min_est = -32767;
static const int int_max_est = +32767;
static const long long_min_est = -2147483647L;
static const long long_max_est = +2147483647L;
static const long long llong_min_est = -9223372036854775807LL;
static const long long llong_max_est = +9223372036854775807LL;
puts("\nSigned limits guaranteed by the standard to be at
least:");
printf("Signed short min %d\n", shrt_min_est);
printf("Signed short max %d\n", shrt_max_est);
printf("Signed int min %d\n", int_min_est);
printf("Signed int max %d\n", int_max_est);
printf("Signed long min %ld\n", long_min_est);
printf("Signed long max %ld\n", long_max_est);
printf("Signed long long min %lld\n", llong_min_est);
printf("Signed long long max %lld\n", llong_max_est);
}
void limits_lookup(void)
{
puts("\nLookup from limits.h:");
printf("Width of Char %d\n", CHAR_BIT);
printf("Signed Char max %d\n", CHAR_MAX);
printf("Signed Char min %d\n", CHAR_MIN);
printf("Unsigned Char max %d\n", UCHAR_MAX);
printf("Signed short min %d\n", SHRT_MIN);
printf("Signed short max %d\n", SHRT_MAX);
printf("Unsigned short max %u\n", USHRT_MAX);
printf("Signed int min %d\n", INT_MIN);
printf("Signed int max %d\n", INT_MAX);
printf("Unsigned int max %u\n", UINT_MAX);
printf("Signed long min %ld\n", LONG_MIN);
printf("Signed long max %ld\n", LONG_MAX);
printf("Unsigned long max %lu\n", ULONG_MAX);
printf("Signed long long min %lld\n", LLONG_MIN);
printf("Signed long long max %lld\n", LLONG_MAX);
printf("Unsigned long long max %llu\n", ULLONG_MAX);
}
void compute_unsigned_max(void)
{
unsigned long long ullm = -1;
unsigned um = -1;
unsigned long ulm = -1;
unsigned short usm = -1;
unsigned char ucm = -1;
puts("\nSimple computation of unsigned maximums:");
printf("Unsigned Char max %d\n", ucm);
printf("Unsigned short max %u\n", usm);
printf("Unsigned int max %u\n", um);
printf("Unsigned long max %lu\n", ulm);
printf("Unsigned long long max %llu\n", ullm);
}
int main(void)
{
limits_lookup();
compute_unsigned_max();
signed_limits_guarantee();
floating_limits();
return 0;
}