如何精确地将浮点数转换为二进制数

时间:2018-11-30 10:11:03

标签: c floating-point binary

我正在编码一个C函数,该函数使我可以将任何float或double转换为包含32位0和1(根据IEEE754标准)的字符串。我将不使用printf,因为其目的是了解它的工作方式并能够存储该字符串。

我从以下视频中采用了微积分方法:https://www.youtube.com/watch?v=8afbTaA-gOQ。它使我能够将浮点数分解为符号的1位,指数的8位和尾数的23位。

我得到了一些不错的结果,但是我的转换器仍然不准确,尾数通常在最后几位是错误的。我用于计算尾数的方法是(其中strnew只是适当长度的malloc):

   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);
    }

对于浮点数(例如0.1),我会得到以下尾数:1001 1001 1001 1001 1001 100我应该得到1001 1001 1001 1001 1001101。这真令人沮丧!我显然在这里丢失了一些东西,我想这与小数点的错误近似有关,所以如果有人知道我应该使用哪种方法而不是我正在使用的方法,我将不胜感激! >

1 个答案:

答案 0 :(得分:0)

  

我的尾数在最后几位经常是错误的。

当转换不完整时,结果应四舍五入。 @Eric Postpischil

下面的示例将中位数从零舍入。

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;
}

更常见的舍入方法:将中途情况舍入到最接近的偶数。

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

进一步,当舍入结果为"1.00000..."时,需要通知调用代码