/* mp6.c by Douglas Jones -- float to int conversion and test */ #include #include /* for exit */ #include /* for int32_t and uint32_t */ /* we use int32_t from stdint.h to force use of 32-bit integers * because C allows type int to be 16, 32 or 64 bits */ /* Preface * Given a floating point number of the form: * s|eeeeeeee|mmmmmmmmmmmmmmmmmmmmmmm * 1| 8 bits | 23 bits sign, exp, mant * | expbits| mantbits = bits in each field * * where: 1.mmmmmmmmmmmmmmmmmmmmmmm the hidden bit when exp != 00000000 * mantfrac = bits right of point * hiddenbits = bits overlapping exponent field * * exp = 01111111 means 0, so exponent = exp - bias, where bias = 0x7F * * 0|01111111|00000000000000000000000 = 1.0 * * therefore the integer part is mant << exponent - mantfrac * shift = exponent - mantfrac * shift = (exp - bias) - mantfrac * shift = exp - (bias + mantfrac) * when exponent = 0, shift = -mantfrac (use >> instead of <<) * when exponent = mantfrac, shift = 0 * when exponent < mantfrac, shift < 0 (meaning use >>) * * note: exponent < mantfrac is (exp - bias) < mantfrac * which is exp < mantfrac + bias * * shift < -mantbits guarantees result is zero, which is * exp - (bias + mantfrac) < -mantbits which is * exp < (bias + mantfrac) - mantbits or * exp < bias + mantfrac - mantbits * * shift > (expbits - hiddenbits) result is overflow, which is * exp - (bias + mantfrac) > (expbits - hiddenbits) which is * exp > (bias + mantfrac) + (expbits - hiddenbits) or * exp > bias + mantfrac + expbits - hiddenbits */ #define expbits 8 #define mantbits 23 #define mantfrac 23 #define hiddenbits 1 #define bias 0x7F #define hidden 0x800000 int32_t ftoint( float f ) { /* convert f to integer, returning 0x80000000 if not possible */ uint32_t fasint = *((uint32_t*)&f); int32_t ret; /* pick apart the number */ uint32_t exp = fasint & (uint32_t)0x7F800000; /* 8 bit exponent */ uint32_t mant = fasint & (uint32_t)0x007FFFFF; /* 23 bit mantissa */ int shift; /* shift count */ /* for explanation of the magic constants that follow, read the notes above */ exp = exp >> mantbits; if (exp > (bias + mantfrac + expbits - hiddenbits)) { /* overflow */ ret = (uint32_t)0x80000000; } else if (exp < (bias + mantfrac - mantbits)) { /* underflow */ ret = 0; } else { /* neither over nor underflow */ mant = mant | hidden; /* set hidden bit */ shift = exp - (bias + mantfrac); if (shift == 0) { ret = mant; } else if (shift > 0) { ret = mant << shift; } else { /* (shift < 0) */ ret = mant >> -shift; } if (f < 0) { ret = -ret; } } return ret; } void testone( float f, int32_t want ) { int32_t got = ftoint( f ); if (got != want) { printf( "fails for x = %0.7g", f ); printf( " ftoint returned %d\n", got ); } } int main() { int32_t i; if (sizeof(float) != 4) { printf( "sizeof(float) != 4" ); exit( EXIT_FAILURE ); } testone( 2.0E9, 2000000000 ); testone( -2.0E9, -2000000000 ); for (i = 1000000000; i >= 1; i = i/10) { testone( (float)i, i ); testone( -(float)i, -i ); } testone( 0.99, 0 ); testone( -0.99, 0 ); testone( 3.0E9, 0x80000000 ); testone( -3.0E9, 0x80000000 ); printf( "Any failures are listed above.\n" ); }