代码之家  ›  专栏  ›  技术社区  ›  biswajit

将二进制浮点“1101.11”转换为十进制(13.75)的正确算法?

  •  3
  • biswajit  · 技术社区  · 12 年前

    我用C语言写了一个程序来转换浮点数 represented in binary ( 1101.11 )转换成十进制( 13.75 ).

    然而,我似乎无法从算法中获得正确的值。

    将二进制浮点数转换为十进制的正确方法是什么?

    我正在使用Dev CPP编译器(32位)。算法定义如下:

    void b2d(double p, double q )
    {
       double rem, dec=0, main, f, i, t=0;
    
       /* integer part operation */    
       while ( p >= 1 )
       {
         rem = (int)fmod(p, 10);
         p = (int)(p / 10);
         dec = dec + rem * pow(2, t);
         t++;
       }
    
       /* fractional part operation */
       t = 1; //assigning '1' to use 't' in new operation
       while( q > 0 )
       {
         main = q * 10;
         q = modf(main, &i); //extration of frational part(q) and integer part(i)
         dec = dec+i*pow(2, -t);
         t++;
       }
    
       printf("\nthe decimal value=%lf\n",dec); //prints the final output
    }
    
    int main()
    {
       double bin, a, f;
    
       printf("Enter binary number to convert:\n");
       scanf("%lf",&bin);
    
       /* separation of integer part and decimal part */
       a = (int)bin;
       f = bin - a;       
       b2d(a, f); // function calling for conversion
    
       getch();
       return 0;
    }
    
    3 回复  |  直到 12 年前
        1
  •  4
  •   Useless    12 年前

    你并不像你认为的那样,把“1101.11”读成 用二进制表示的浮点数 。你把它当作 转换为IEEE双精度浮点值的十进制浮点数 然后 试图改变基地。

    这个中间步骤固有的不精确性是您出现问题的原因。

    Vicky建议的一个更好的方法是:

    1. 将“1101.11”作为字符串或文本行读取
    2. 转换整数部分和小数部分( whole=b1101=13 numerator=b11=3 , denominator=4 )
    3. 把这些重新组合成 whole + numerator/denominator = 13.75
        2
  •  4
  •   brice    12 年前

    解决方案

    以下将按预期工作:

    输出:

    ➤ gcc bin2dec.c -lm -o bin2dec && bin2dec
    1101.11 -> 13.750000
    1101 -> 13.000000
    1101. -> 13.000000
    .11 -> 0.750000
    

    代码( bin2dec.c ):

    #include <stdio.h>
    #include <math.h>
    
    double convert(const char binary[]){
      int bi,i;
      int len = 0;
      int dot = -1;
      double result = 0;
    
      for(bi = 0; binary[bi] != '\0'; bi++){
        if(binary[bi] == '.'){
          dot = bi;
        }
        len++;
      }
      if(dot == -1)
        dot=len;
    
      for(i = dot; i >= 0 ; i--){
        if (binary[i] == '1'){
          result += (double) pow(2,(dot-i-1));
        }
      }
      for(i=dot; binary[i] != '\0'; i++){
        if (binary[i] == '1'){
          result += 1.0/(double) pow(2.0,(double)(i-dot));
        }
      }
      return result;
    }
    
    int main()
    {
       char  bin[] = "1101.11";
       char  bin1[] = "1101";
       char  bin2[] = "1101.";
       char  bin3[] = ".11";
    
       printf("%s -> %f\n",bin, convert(bin)); 
       printf("%s -> %f\n",bin1, convert(bin1)); 
       printf("%s -> %f\n",bin2, convert(bin2)); 
       printf("%s -> %f\n",bin3, convert(bin3)); 
    
       return 0;
    }
    

    解释

    上述代码的工作原理是首先找到数字中小数点的索引。

    一旦知道了这一点,它就会从该索引向前和向后遍历字符串,并将适当的值添加到 result 变量

    第一个循环从小数点向后走,如果字符为 1 。它将离小数点的距离作为2的幂,减去1,索引才能正确。即,它累积:

    pow(2,<distance-from-decimal-point>)
    

    当索引到达字符串的开头时,循环停止。

    第二个循环向前走到字符串的末尾,并处理分数部分 as expected 它还使用了与索引的距离,但这次累积了小数部分:

    1/pow(2,<distance-from-decimal-point>)
    

    已制定的示例:

    1101.11 = 1101 + 0.11
    
    1101 = 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 8 + 4 + 0 + 1 = 13
    
    0.11 = 1/(2^1) + 1/(2^2) = 0.5 + 0.25 = 0.75
    
    1101.11 = 13.75
    

    注意格式错误的输入。“10gsh.99701072.67812”会给你一个结果。意义不大:)

        3
  •  3
  •   taocp    12 年前

    这段代码的行为异常:我添加了一些简单的print语句

      while(q>0)
      {
         double i;
         main=q*10.0;
         q=modf(main, &i); //extration of frational part(q) and integer part(i)
         cout << "main = " << main << " frac part " << q << " int part " << i << endl;
         cin.get();
         dec=dec+i*pow(2,-t);
         t++;
      }
    

    当您输入1101.11时,会显示以下输出:

    Enter binary number to convert(e.g: 1101.11 which will be 13.75 in decimal):
    1101.11
    bin in main 1101.11
    p  1101 q 0.11
    
    //inside the above while loop code
    main = 1.1 frac part 0.1 int part 1
    main = 1 frac part 1 int part 0  //^^^^^Error, given main=1, it should output integer part 1, fraction part 0
    main = 10 frac part 1 int part 9  //^^^^^same strange error here, it should exit while already
    

    所以你们得到了错误的结果。我测试过 modf 与输入1分开,它给出了正确的结果。

    所以我的猜测是,你正在把二进制数读为double,然后试图把这个double转换回二进制。尽管这表明数字的准确性 1101.11 。正如@Useless所建议的,您可能需要将数字读取为字符串,计算出小数点前后的子字符串 . 然后将这两部分分别转换成十进制。