0

I'm coding a C function that allows me to transform any float or double into a string containing 32 bits of 0s and 1s (according to IEEE754 standard). I'm not going to make use of printf as the objective is to understand the way it works and be able to store the string.

I took the calculus method from this video: https://www.youtube.com/watch?v=8afbTaA-gOQ. It enabled me to deconstruct the floats into 1 bit for the sign, 8 bits for the exponent and 23 bits for the mantissa.

I'm getting some pretty good results, but my converter is still not accurate, and my mantissa is often wrong in the last bits. The method I use to calculate the mantissa is (where strnew is just a malloc of the appropriate length):

   char *ft_double_decimals(double n, int len)
   {
        char    *decimals;
        int     i;

        if (!(decimals = ft_strnew(len)))
            return (NULL);
        i = 0;
        while (i < len)
        {
            n = n * 2;
            decimals[i++] = (n >= 1) ? '1' : '0';
            n = n - (int)n;
        }
        return (decimals);
    }

For a float such as 0.1 I get this mantissa: 1001 1001 1001 1001 1001 100 where I should get 1001 1001 1001 1001 1001 101. This is so frustrating! I'm obviously missing something here, and I guess it has something to do with a wrong approximation of the decimals, so if someone knows what method I should use instead of the one I'm using I'll be very grateful!

  • Possible duplicate of [How to print out each bit of a floating point number?](https://stackoverflow.com/questions/1697425/how-to-print-out-each-bit-of-a-floating-point-number) – Giovanni Cerretani Nov 30 '18 at 10:41
  • You need to round the discarded bits, which the video did not discuss. Converting the `double` to a `float` would do that, except there are also issues of exponent range. – Eric Postpischil Nov 30 '18 at 11:43
  • What are you really trying to do? (a) You already have a 32-bit `float` and want to show the bits that represent it. (b) You have a floating-point object in a platform that may or may not use IEEE-754, and you want to show its IEEE-754 32-bit binary floating-point encoding. (c) You have a decimal numeral (as in a string) and want to shows its IEEE-754 32-bit binary floating-point encoding. (d) Something else. – Eric Postpischil Nov 30 '18 at 15:03
  • @EricPostpischil absolutely. The code provided by the answer below is perfect for this purpose – pablito9294 Nov 30 '18 at 15:34

1 Answers1

0

my mantissa is often wrong in the last bits.

When the conversion is incomplete, results should be rounded. @Eric Postpischil

The below rounds half-way cases away from zero.

char *ft_double_decimals(double n, int len) {
  char *decimals;
  int i;

  if (!(decimals = ft_strnew(len)))
    return (NULL);
  i = 0;
  while (i < len) {
    n = n * 2;
    decimals[i++] = (n >= 1) ? '1' : '0';
    n = n - (int) n;
  }

  // Add rounding code
  if (n >= 0.5) {
    int carry = 1;
    while (i > 0) {
      i--;
      int sum = decimals[i] - '0' + carry;
      decimals[i] = sum % 2 + '0';
      carry = sum / 2;
    }
    if (i == 0 && carry > 0) {
      // Rounding into the "one's" digit"
      // TBD code to indicate to the caller that event
    }
  }

  return (decimals);
}

int main(void) {
  printf("%s\n", ft_double_decimals(0.1f, 23)); // --> 00011001100110011001101
  return 0;
}

A more common rounding: round half-way cases to nearest even.

if (n >= 0.5 && (n > 0.5 || ((i > 0) && decimals[i-1] > '0'))) {

Further, calling code needs to be informed when the rounded result is "1.00000..."

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256