Advertisement
drankinatty

Convert float to IEEE-754 Single Precision Binary Number

Feb 16th, 2016
848
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.08 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <errno.h>
  6.  
  7. #if defined(__LP64__) || defined(_LP64)
  8. # define BUILD_64   1
  9. #endif
  10.  
  11. /* constants for word and double-word size */
  12. #define WDSZ 64
  13. #define DWSZ 128
  14.  
  15. inline int getmsb (unsigned long x);
  16. char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep);
  17. char *binstr (unsigned long n);
  18. char *fpfrc_bin (float fvalue);
  19. void show_fltmem (float f);
  20. void show_ieee754str (char *s);
  21. void show_ieee754 (float f);
  22. float xstrtof (char *str);
  23. char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac);
  24.  
  25. int main (int argc, char** argv) {
  26.  
  27.     if (argc < 2) {
  28.         fprintf (stderr, "error: insufficient input. Usage: %s float\n", argv[0]);
  29.         return 1;
  30.     }
  31.  
  32.     char *dp = strchr (argv[1], '.');   /* pointer to decimal point */
  33.     int dec = atoi (argv[1]);           /* integer of decimal part  */
  34.     int frc = (dp) ? atoi (dp + 1) : 0; /* integer of fraction part */
  35.  
  36.     /* output string input values  */
  37.     printf ("\nString Values:\n");
  38.     printf (" string   : %s\n whole    : %d\n fraction : %d\n\n", argv[1], dec, frc);
  39.  
  40.     float fvalue = xstrtof (argv[1]);
  41.     float ffrc = fvalue - dec;
  42.     int signbit = (fvalue >= 0) ? 0 : 1;
  43.  
  44.     /* output float input values   */
  45.     printf ("Float Values:\n");
  46.     printf (" decimal  : %d\n fraction : %f\n\n", dec, ffrc);
  47.  
  48.     char *fstring = fpfrc_bin (fvalue);         /* fraction part in binary  */
  49.     char *bs = binstr ((unsigned long) dec);    /* decimal part in binary   */
  50.  
  51.     /* output binary values decimal part/fraction part */
  52.     printf ("Binary Values:\n");
  53.     printf (" decimal  : %s\n fraction : %s\n sign bit : %d\n\n", bs, fstring, signbit);
  54.  
  55.     /* quick hack of exp bias, biased value, conversion to binary   */
  56.     int bias = (int) strlen (bs) - 1;
  57.     int biasexp = 127+bias;
  58.     char *binexp = binstr ((unsigned long) biasexp);
  59.  
  60.     /* output summary of biased IEEE-754 exponent */
  61.     printf ("Normalization for biased exponent:\n");
  62.     printf ("\n %s.%s  =>  %s.%s%s\n\n", bs, fstring, "1", (bs+1), fstring);
  63.     printf ("     exponent bias: %d\n unbiased exponent: 127\n", bias);
  64.     printf (" __________________+____\n\n");
  65.     printf ("   biased exponent: %3d\n   binary exponent: %s\n\n", biasexp, binexp);
  66.  
  67.     /* output summary of IEEE-754 mantissa */
  68.     printf ("Conversion to 'hidden bit' format to form mantissa:\n\n");
  69.     printf (" %s.%s%s  =>  %s%s\n\n", "1", (bs+1), fstring, (bs+1), fstring);
  70.  
  71.     /* form IEEE-754 binary representation from values computed */
  72.     char *ieee754str = form_ieee754SPstr (signbit, binexp, bs, fstring);
  73.  
  74.     /* output formatted complete IEEE-754 binary - from computed values above */
  75.     printf ("IEEE-754 Single Precision Floating Point Representation (caclulated value)\n\n");
  76.     show_ieee754str (ieee754str);
  77.  
  78.     /* output formatted complete IEEE-754 binary - from float value in memory */
  79.     printf ("IEEE-754 Single Precision Floating Point Representation (memory value)\n\n");
  80.     show_ieee754 (fvalue);
  81.  
  82.     /* output float, binary and integer equivalent */
  83.     show_fltmem (fvalue);
  84.  
  85.     if (bs) free (bs);
  86.     if (binexp) free (binexp);
  87.     if (ieee754str) free (ieee754str);
  88.  
  89.     return 0;
  90. }
  91.  
  92. /** single-precision float in memory
  93.  *  output the float, equivalent unsigned int, and
  94.  *  binary representation of the number in memory
  95.  */
  96.  
  97. void show_fltmem (float f)
  98. {
  99.     unsigned int i = *(unsigned int *)&f;
  100.  
  101.     printf ("\nRepresentations of float value in memory:\n\n");
  102.     printf ("    The float value entered : %f\n\n", f);
  103.     printf ("    binary value in memory  : %s\n\n", fmt_binstr (i, 32, 8, '-'));
  104.     printf ("    bits as unsigned int    : %u\n\n", i);
  105. }
  106.  
  107. /** most significant bit.
  108.  *  return the 0-based most significant bit for any
  109.  *  unsigned value using the bit-scan-right assembly
  110.  *  directive.
  111.  */
  112. inline int getmsb (unsigned long x)
  113. {
  114. #ifdef BUILD_64
  115.     asm ("bsrq %0, %0" : "=r" (x) : "0" (x));
  116. #else
  117.     asm ("bsr %0, %0" : "=r" (x) : "0" (x));
  118. #endif
  119.     return x;
  120. }
  121.  
  122. /** returns pointer to formatted binary representation of 'n' zero padded to 'sz'.
  123.  *  returns pointer to string contianing formatted binary representation of
  124.  *  unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
  125.  *  'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
  126.  */
  127. char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep) {
  128.  
  129.     static char s[DWSZ + 1] = {0};
  130.     char *p = s + DWSZ;
  131.     unsigned char i;
  132.  
  133.     for (i = 0; i < sz; i++) {
  134.         p--;
  135.         if (i > 0 && szs > 0 && i % szs == 0)
  136.             *p-- = sep;
  137.         *p = (n >> i & 1) ? '1' : '0';
  138.     }
  139.  
  140.     return p;
  141. }
  142.  
  143. /** returns an allocated string containing unpadded binary
  144.  *  representation of the integer value 'n'. This value must
  145.  *  be assigned to a pointer and freed to prevent leaks.
  146.  */
  147. char *binstr (unsigned long n)
  148. {
  149.     unsigned char msb = getmsb (n);
  150.     char *s = calloc (msb + 2, sizeof *s);
  151.     char *p = s + msb;
  152.     unsigned char i;
  153.  
  154.     for (i = 0; i < msb+1; i++) {
  155.         *p-- = (n >> i & 1) ? '1' : '0';
  156.     }
  157.  
  158.     return s;
  159. }
  160.  
  161. /** return string containing binary representation of fraction
  162.  *  The function takes a float as an argument and computes the
  163.  *  binary representation of the fractional part of the float,
  164.  *  On success, the function returns a null-terminated string
  165.  *  containing the binary value, or NULL otherwise. MAXD of 24
  166.  *  (23 + null-term) for Single-Precision mantissa, 53
  167.  *  (52 + null-term) for Double-Precision mantissa.
  168.  */
  169. char *fpfrc_bin (float fvalue)
  170. {
  171.     float fv = fvalue - (int)fvalue;
  172.     int MAXD = 24;
  173.     char *fvs = calloc (MAXD, sizeof *fvs);
  174.     if (!fvs) {
  175.         fprintf (stderr, "%s()_error: allocation failed.\n", __func__);
  176.         return NULL;
  177.     }
  178.     char *p = fvs;
  179.     unsigned char it = 0;
  180.  
  181.     while (fv > 0 && it < MAXD)
  182.     {
  183.         fv = fv * 2.0;
  184.         *p++ = ((int)fv) ? '1' : '0';
  185.         fv = ((int)fv >= 1) ? fv - 1.0 : fv;
  186.         it++;
  187.     }
  188.  
  189.     return fvs;
  190. }
  191.  
  192. /** formatted output of ieee-754 representation of float from binary string.
  193.  */
  194. void show_ieee754str (char *s)
  195. {
  196.     printf (" ");
  197.     while (*s)
  198.         printf (" %c", *s++);
  199.     printf ("\n");
  200.     printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n");
  201.     printf (" |s|      exp      |                  mantissa                   |\n\n");
  202. }
  203.  
  204. /** formatted output of ieee-754 representation of float from stored value.
  205.  */
  206. void show_ieee754 (float f)
  207. {
  208.     printf ("  ");
  209.     int i = 32;
  210.     while (i) {
  211.         i--;
  212.         printf ("%d ", ((*(int *)&f >> i) & 0x1));
  213.     }
  214.     printf ("\n");
  215.     printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n");
  216.     printf (" |s|      exp      |                  mantissa                   |\n\n");
  217. }
  218.  
  219. /** string to float with error checking. */
  220. float xstrtof (char *str)
  221. {
  222.     char *endptr = NULL;
  223.     errno = 0;
  224.  
  225.     float val = strtof (str, &endptr);
  226.  
  227.     /* Check for various possible errors */
  228.     if ((errno == ERANGE && (val == HUGE_VALF || val == HUGE_VALL)) ||
  229.         (errno != 0 && val == 0)) {
  230.         perror ("strtof");
  231.         exit (EXIT_FAILURE);
  232.     }
  233.  
  234.     if (endptr == str) {
  235.         fprintf (stderr, "No digits were found\n");
  236.         exit (EXIT_FAILURE);
  237.     }
  238.  
  239.     return val;
  240. }
  241.  
  242. /** form IEEE-754 binary representation from computed  values for the
  243.  *  sign bit, biased exponent binary string, decimal binary string, and
  244.  *  fractional binary string, forming the 23-bit mantissa from the decimal
  245.  *  and fractional strings, filling with '0' as needed. An allocated
  246.  *  string containing the IEEE-754 Single-Precision representation is
  247.  *  returned.
  248.  */
  249. char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac)
  250. {
  251.     char *str = calloc (33, sizeof *str);
  252.     char *p = str + 1;
  253.     char *sp = dec + 1;                         /* leading 1 - hidden bit   */
  254.     size_t fsl = strlen (frac);                 /* length of fractional str */
  255.     size_t manbits = fsl + strlen (sp);         /* available mantissa bits  */
  256.     size_t mdiff = 23 - manbits;                /* diff from required 23    */
  257.  
  258.     *str = (sign == 0) ? '0' : '1';             /* set sign bit in string   */
  259.  
  260.     memcpy (p, exp, 8);                         /* set biased exponent      */
  261.     p += 8;
  262.  
  263.     while (*sp) { *p = *sp++; p++; };           /* mantissa - decimal bits  */
  264.  
  265.     if (manbits < 23)                           /* test < 23 bits available */
  266.     {
  267.         memcpy (p, frac, fsl);                  /* copy fractional bits     */
  268.         p += fsl;                               /* increment pointer        */
  269.         register size_t it = 0;
  270.         if (mdiff > 0)                          /* fill remaining mantissa  */
  271.             for (it = 0; it < mdiff; it++)
  272.             {
  273.                 *p = '0';
  274.                 p++;
  275.             }
  276.     }
  277.     else
  278.     {
  279.         memcpy (p, frac, 23);                   /* fill mantissa w/23 bits  */
  280.     }
  281.  
  282.     return str;
  283. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement