Question

I have written a program in C to convert a floating point number represented in binary (1101.11) into a decimal (13.75).

However, I cannot seem to get the correct value out of the algorithm.

What is the correct method for converting a binary floating point number into a decimal?

I am using Dev CPP compiler (32 bit). The algorithm is defined below:

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;
}
Was it helpful?

Solution 3

This piece of code behaves abnormally: I added some simple print statement

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

When you input 1101.11, the following output shown:

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

So you got wrong result. I tested modf separately with input 1, it gave correct result.

So my guess is that you are reading the binary number as double, then tries to convert this double to binary back. There might be something going on under the hood for the precision of number though it shows that it is 1101.11. As suggested by @Useless, You may need to read the number as a string, figure out the substring before and after the decimal point . Then convert this two part into decimal separately.

OTHER TIPS

You are not, as you believe, reading "1101.11" as a floating point number represented in binary. You are reading it as a base-10 floating point number converted into an IEEE double-precision floating-point value, and then trying to change the base.

The inherent imprecision of this intermediate step is the reason for your problem.

A better approach, as suggested by Vicky, is to:

  1. read "1101.11" as a string or line of text
  2. convert the whole and fractional parts (whole=b1101=13 and numerator=b11=3, denominator=4)
  3. re-combine these into whole + numerator/denominator = 13.75

Solution

The following will work as expected:

Output:

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

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

Explanation

The above code works by first finding the index of the decimal point in the number.

Once that is known, it walks the string both backwards and forwards from this index, adding the appropriate value to the result variable.

The first loop walks backwards from the decimal point and accumulates the powers of 2 if the character is 1. It takes the distance from the decimal point as the power of two, minus one for the indexing to be correct. Ie, it accumulates :

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

The loop stops when the index reaches the beginning of the string.

The second loop walks forward until the end of the string, and deals with the fractional part as expected it also uses the distance from the index, but this time accumulates fractional parts:

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

Worked out example:

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

Beware of malformed input. "10gsh.9701072.67812" will give you a result. It won't mean much :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top