3

2 進数 ( )で表される1101.11浮動小数点数を10 進数 ( )に変換するプログラムを C で作成しました13.75

ただし、アルゴリズムから正しい値を取得できないようです。

2 進浮動小数点数を 10 進数に変換する正しい方法は何ですか?

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

3 に答える 3

4

あなたが信じているように、「1101.11」をバイナリで表された浮動小数点数として読んでいるわけではありません。IEEE 倍精度浮動小数点値に変換された基数 10 の浮動小数点数として読み取り、基数変更しようとしています。

この中間ステップに固有の不正確さが問題の原因です。

Vicky が提案するより良いアプローチは、次のとおりです。

  1. 「1101.11」を文字列またはテキスト行として読み取ります
  2. 全体と小数部分を変換します (whole=b1101=13numerator=b11=3, denominator=4)
  3. これらを再び組み合わせてwhole + numerator/denominator = 13.75
于 2013-04-02T16:14:10.200 に答える
4

解決

以下は期待どおりに機能します。

出力:

➤ 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変数に追加します。

最初のループは小数点から逆方向に進み、文字が の場合は 2 のべき乗を累積し1ます。インデックスを正しくするには、小数点からの距離を 2 の累乗から 1 を引いた値にします。すなわち、それは蓄積します:

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

インデックスが文字列の先頭に到達すると、ループは停止します。

2 番目のループは、文字列の末尾まで順方向に進み、期待どおりに小数部分を処理します。インデックスからの距離も使用しますが、今回は小数部分を累積します。

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.9701072.67812」で結果が得られます。それはあまり意味がありません:)

于 2013-04-02T16:24:37.177 に答える
3

このコードは異常な動作をします: 簡単な 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で個別にテストしたところ、正しい結果が得られました。

したがって、私の推測では、2 進数を double として読み取っていて、この double を 2 進数に変換しようとしていると思います。であることが示されていますが、数値の精度について内部で何かが起こっている可能性があります1101.11。@Useless で提案されているように、数値を文字列として読み取り、小数点の前後の部分文字列を把握し、.この 2 つの部分を個別に 10 進数に変換する必要がある場合があります。

于 2013-04-02T16:19:06.900 に答える