Not so long ago, I had the opportunity to write a similar piece of code that you and others might find useful. It takes a character string representing a floating-point number as the first argument to the program and converts the string into an IEEE-754 Single Precision Floating Point representation along with its equivalent integer value. Take a look and let me know if you have any questions.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <errno.h> #if defined(__LP64__) || defined(_LP64) # define BUILD_64 1 #endif /* constants for word and double-word size */ #define WDSZ 64 #define DWSZ 128 inline int getmsb (unsigned long x); char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep); char *binstr (unsigned long n); char *fpfrc_bin (float fvalue); void show_fltmem (float f); void show_ieee754str (char *s); void show_ieee754 (float f); float xstrtof (char *str); char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac); int main (int argc, char** argv) { if (argc < 2) { fprintf (stderr, "error: insufficient input. Usage: %s float\n", argv[0]); return 1; } char *dp = strchr (argv[1], '.'); /* pointer to decimal point */ int dec = atoi (argv[1]); /* integer of decimal part */ int frc = (dp) ? atoi (dp + 1) : 0; /* integer of fraction part */ /* output string input values */ printf ("\nString Values:\n"); printf (" string : %s\n whole : %d\n fraction : %d\n\n", argv[1], dec, frc); float fvalue = xstrtof (argv[1]); float ffrc = fvalue - dec; int signbit = (fvalue >= 0) ? 0 : 1; /* output float input values */ printf ("Float Values:\n"); printf (" decimal : %d\n fraction : %f\n\n", dec, ffrc); char *fstring = fpfrc_bin (fvalue); /* fraction part in binary */ char *bs = binstr ((unsigned long) dec); /* decimal part in binary */ /* output binary values decimal part/fraction part */ printf ("Binary Values:\n"); printf (" decimal : %s\n fraction : %s\n sign bit : %d\n\n", bs, fstring, signbit); /* quick hack of exp bias, biased value, conversion to binary */ int bias = (int) strlen (bs) - 1; int biasexp = 127+bias; char *binexp = binstr ((unsigned long) biasexp); /* output summary of biased IEEE-754 exponent */ printf ("Normalization for biased exponent:\n"); printf ("\n %s.%s => %s.%s%s\n\n", bs, fstring, "1", (bs+1), fstring); printf (" exponent bias: %d\n unbiased exponent: 127\n", bias); printf (" __________________+____\n\n"); printf (" biased exponent: %3d\n binary exponent: %s\n\n", biasexp, binexp); /* output summary of IEEE-754 mantissa */ printf ("Conversion to 'hidden bit' format to form mantissa:\n\n"); printf (" %s.%s%s => %s%s\n\n", "1", (bs+1), fstring, (bs+1), fstring); /* form IEEE-754 binary representation from values computed */ char *ieee754str = form_ieee754SPstr (signbit, binexp, bs, fstring); /* output formatted complete IEEE-754 binary - from computed values above */ printf ("IEEE-754 Single Precision Floating Point Representation (caclulated value)\n\n"); show_ieee754str (ieee754str); /* output formatted complete IEEE-754 binary - from float value in memory */ printf ("IEEE-754 Single Precision Floating Point Representation (memory value)\n\n"); show_ieee754 (fvalue); /* output float, binary and integer equivalent */ show_fltmem (fvalue); if (bs) free (bs); if (binexp) free (binexp); if (ieee754str) free (ieee754str); return 0; } /** single-precision float in memory * output the float, equivalent unsigned int, and * binary representation of the number in memory */ void show_fltmem (float f) { unsigned int i = *(unsigned int *)&f; printf ("\nRepresentations of float value in memory:\n\n"); printf (" The float value entered : %f\n\n", f); printf (" binary value in memory : %s\n\n", fmt_binstr (i, 32, 8, '-')); printf (" bits as unsigned int : %u\n\n", i); } /** most significant bit. * return the 0-based most significant bit for any * unsigned value using the bit-scan-right assembly * directive. */ inline int getmsb (unsigned long x) { #ifdef BUILD_64 asm ("bsrq %0, %0" : "=r" (x) : "0" (x)); #else asm ("bsr %0, %0" : "=r" (x) : "0" (x)); #endif return x; } /** returns pointer to formatted binary representation of 'n' zero padded to 'sz'. * returns pointer to string contianing formatted binary representation of * unsigned 64-bit (or less ) value zero padded to 'sz' digits with char * 'sep' placed every 'szs' digits. (eg 10001010 -> 1000-1010). */ char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep) { static char s[DWSZ + 1] = {0}; char *p = s + DWSZ; unsigned char i; for (i = 0; i < sz; i++) { p--; if (i > 0 && szs > 0 && i % szs == 0) *p-- = sep; *p = (n >> i & 1) ? '1' : '0'; } return p; } /** returns an allocated string containing unpadded binary * representation of the integer value 'n'. This value must * be assigned to a pointer and freed to prevent leaks. */ char *binstr (unsigned long n) { unsigned char msb = getmsb (n); char *s = calloc (msb + 2, sizeof *s); char *p = s + msb; unsigned char i; for (i = 0; i < msb+1; i++) { *p-- = (n >> i & 1) ? '1' : '0'; } return s; } /** return string containing binary representation of fraction * The function takes a float as an argument and computes the * binary representation of the fractional part of the float, * On success, the function returns a null-terminated string * containing the binary value, or NULL otherwise. MAXD of 24 * (23 + null-term) for Single-Precision mantissa, 53 * (52 + null-term) for Double-Precision mantissa. */ char *fpfrc_bin (float fvalue) { float fv = fvalue - (int)fvalue; int MAXD = 24; char *fvs = calloc (MAXD, sizeof *fvs); if (!fvs) { fprintf (stderr, "%s()_error: allocation failed.\n", __func__); return NULL; } char *p = fvs; unsigned char it = 0; while (fv > 0 && it < MAXD) { fv = fv * 2.0; *p++ = ((int)fv) ? '1' : '0'; fv = ((int)fv >= 1) ? fv - 1.0 : fv; it++; } return fvs; } /** formatted output of ieee-754 representation of float from binary string. */ void show_ieee754str (char *s) { printf (" "); while (*s) printf (" %c", *s++); printf ("\n"); printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n"); printf (" |s| exp | mantissa |\n\n"); } /** formatted output of ieee-754 representation of float from stored value. */ void show_ieee754 (float f) { printf (" "); int i = 32; while (i) { i--; printf ("%d ", ((*(int *)&f >> i) & 0x1)); } printf ("\n"); printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n"); printf (" |s| exp | mantissa |\n\n"); } /** string to float with error checking. */ float xstrtof (char *str) { char *endptr = NULL; errno = 0; float val = strtof (str, &endptr); /* Check for various possible errors */ if ((errno == ERANGE && (val == HUGE_VALF || val == HUGE_VALL)) || (errno != 0 && val == 0)) { perror ("strtof"); exit (EXIT_FAILURE); } if (endptr == str) { fprintf (stderr, "No digits were found\n"); exit (EXIT_FAILURE); } return val; } /** form IEEE-754 binary representation from computed values for the * sign bit, biased exponent binary string, decimal binary string, and * fractional binary string, forming the 23-bit mantissa from the decimal * and fractional strings, filling with '0' as needed. An allocated * string containing the IEEE-754 Single-Precision representation is * returned. */ char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac) { char *str = calloc (33, sizeof *str); char *p = str + 1; char *sp = dec + 1; /* leading 1 - hidden bit */ size_t fsl = strlen (frac); /* length of fractional str */ size_t manbits = fsl + strlen (sp); /* available mantissa bits */ size_t mdiff = 23 - manbits; /* diff from required 23 */ *str = (sign == 0) ? '0' : '1'; /* set sign bit in string */ memcpy (p, exp, 8); /* set biased exponent */ p += 8; while (*sp) { *p = *sp++; p++; }; /* mantissa - decimal bits */ if (manbits < 23) /* test < 23 bits available */ { memcpy (p, frac, fsl); /* copy fractional bits */ p += fsl; /* increment pointer */ register size_t it = 0; if (mdiff > 0) /* fill remaining mantissa */ for (it = 0; it < mdiff; it++) { *p = '0'; p++; } } else { memcpy (p, frac, 23); /* fill mantissa w/23 bits */ } return str; }
Usage / Output Example
$ ./bin/ieee754cvt 123.456 String Values: string : 123.456 whole : 123 fraction : 456 Float Values: decimal : 123 fraction : 0.456001 Binary Values: decimal : 1111011 fraction : 01110100101111001 sign bit : 0 Normalization for biased exponent: 1111011.01110100101111001 => 1.11101101110100101111001 exponent bias: 6 unbiased exponent: 127 __________________+____ biased exponent: 133 binary exponent: 10000101 Conversion to 'hidden bit' format to form mantissa: 1.11101101110100101111001 => 11101101110100101111001 IEEE-754 Single Precision Floating Point Representation (caclulated value) 0 1 0 0 0 0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 1 |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -| |s| exp | mantissa | IEEE-754 Single Precision Floating Point Representation (memory value) 0 1 0 0 0 0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 1 |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -| |s| exp | mantissa | Representations of float value in memory: The float value entered : 123.456001 binary value in memory : 01000010-11110110-11101001-01111001 bits as unsigned int : 1123477881