-1

CODE description: Code to convert float to ascii to be displayed on a touchscreen.

It rounds of decimals after 0.7 , i.e. it does not display 0.8 and 0.9 .I have tried a lot of debugging but i am not able to solve this. I think the problem is with the switch case. How can i debug?

The code:

void ftoa(float Value, char* Buffer) //begin
 { 

 union 
  { 
     float f; 

     struct 
     { 
         unsigned int    mantissa_lo : 16; //initialise
         unsigned int    mantissa_hi : 7;     
         unsigned int     exponent : 8; 
         unsigned int     sign : 1; 
     }; 
  } helper; 

  unsigned long mantissa; 
  signed char exponent; 
  unsigned int int_part; 
  char frac_part[3]; 
  int i, count = 0; 
 int rz;

 rz=16;

   helper.f = Value; 

  mantissa = helper.mantissa_lo; //mantissa is LS 23 bits 
mantissa = helper.f;
  mantissa += ((unsigned long) helper.mantissa_hi << 16); 

  mantissa += 0x00800000; //add the 24th bit to get 1.mmmm^eeee format 
  //exponent is biased by 127 
  exponent = (signed char) helper.exponent - 127; 
  exponent = 3;


  if (exponent > 18) //too big to shove into 8 chars 
  { 
     Buffer[0] = 'I'; 
     Buffer[1] = 'n'; 
     Buffer[2] = 'f'; 
     Buffer[3] = '\0'; 
     return; 
  } 


  if (exponent < -3) //too small to resolve (resolution of 1/8) 
  { 
     Buffer[0] = '0'; 
     Buffer[1] = '\0'; 
     return; 
  } 

  count = 0; 

   //add negative sign (if applicable) 
//  if (helper.sign) 
//    { 
//        Buffer[0] = '-'; 
//      count++; 
// } 

 //get the integer part 
 int_part = mantissa >> (23 - exponent);     
 //convert to string 
 itoa(int_part,rz, &Buffer[count]); 

 //find the end of the integer 
 for (i = 0; i < 7; i++) 
     if (Buffer[i] == '\0') 
     { 
         count = i; 
         break; 
     } 



 if (count > 6) //not enough room in the buffer for the frac part 
     return; 

 //add the decimal point     
  Buffer[count++] = '.'; 

  //use switch to resolve the fractional part 
  switch (0x00000007 & (mantissa  >> (20 - exponent))) //for the fractional part.
  { 
     case 0: 
         frac_part[0] = '0'; 
   //      frac_part[1] = '0'; 
   //      frac_part[2] = '0'; 
         break; 
     case 1: 
         frac_part[0] = '1'; 
        // frac_part[1] = '2'; 
        // frac_part[2] = '5';             
         break; 
     case 2: 
         frac_part[0] = '2'; 
        // frac_part[1] = '5'; 
        // frac_part[2] = '0';             
         break; 
     case 3: 
         frac_part[0] = '3'; 
        // frac_part[1] = '7'; 
        // frac_part[2] = '5';             
         break; 
     case 4: 
         frac_part[0] = '4'; 
        // frac_part[1] = '0'; 
        // frac_part[2] = '0';             
         break; 
     case 5: 
         frac_part[0] = '5'; 
        // frac_part[1] = '2'; 
        // frac_part[2] = '5';             
         break; 
     case 6: 
         frac_part[0] = '6'; 
        // frac_part[1] = '5'; 
         //frac_part[2] = '0';             
         break; 
     case 7: 
         frac_part[0] = '7'; 
       //  frac_part[1] = '7'; 
       //  frac_part[2] = '5';                     
         break; 

     case 8: 
         frac_part[0] = '8';   //switch case
       //  frac_part[1] = '7'; 
       //  frac_part[2] = '5';                     
         break; 
     case 9: 
         frac_part[0] = '9'; 
       //  frac_part[1] = '7'; 
       //  frac_part[2] = '5';                     
         break;
    default :
          frac_part[0] = '8';
          break;

  } 

  //add the fractional part to the output string 
  for (i = 0; i < 3; i++) 
     if (count < 7) 
         Buffer[count++] = frac_part[i]; 

  //make sure the output is terminated 
  Buffer[count] = '\0'; 

 for ( i=0; i < 19; i++ )
 {
     cArr[i] = Buffer[i];
 }   

    }

         //It rounds of decimals after 0.7 , i.e. it does not display 0.8 and 0.9 
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • 1
    Why don't you use `sprintf()`? You should definitely be able to display one digit after the decimal point, [example](http://ideone.com/CeEdWI). – Alexey Frunze Mar 07 '13 at 13:06
  • 1
    You realise that your entire switch/case can be replaced with just: `frac_part[0] = '0' + (0x00000007 & (mantissa >> (20 - exponent)))`? Of course it will still be incorrect, but it is equivalent. The code is a binary floating point implementation, and you are trying to interpret it as decimal. – Clifford Mar 07 '13 at 15:31
  • Thankyou for your reply guys. I cannot use sprintf() my compiler does not support it. I am working on a LCD module . – Ashish Gupta Mar 08 '13 at 07:28
  • Can anyone please suggest some ftoa() code please. i.e float to ascii. – Ashish Gupta Mar 08 '13 at 07:29
  • That seems slightly beyond the scope of a comment, especially as it's orthogonal to the question posed. However, as a starting point, I would suggest a simple solution might be to multiply your number by as many 10s as you want fractional digits, converting to integer, and then adding a '.' in the right place. – JasonD Mar 08 '13 at 07:50

1 Answers1

2

This looks a bit over complicated, but one obvious thing is:

switch (0x00000007 & ...

That's never going to give you any switch cases of 8 or above.

And I don't know how you expect to extract a base-10 fraction, using shifts and masks. You probably want a multiply by 10 in there somewhere.

JasonD
  • 16,464
  • 2
  • 29
  • 44
  • This is what comes from trying to repurpose some code that prints stuff out in eighths without reading and understanding it first. – uɐɪ Mar 07 '13 at 13:40
  • Thankyou guys. I am planning to write my own code. This one is unnecessarily complicated. By the way can anyone please tell me what does switch(0x7 && (mantissa >> (20 - exponent))) do? – Ashish Gupta Mar 08 '13 at 07:11
  • Mantissa is your value, raised to a power of 2 (exponent). So this calculates your value multiplied by eight (as it shifts by 3 fewer bits than required to get the integer part), as an integer, and masks off the bottom 3 bits. Essentially it's the fraction in eighths. – JasonD Mar 08 '13 at 07:19