CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

The same old float printf problem
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
VanHauser



Joined: 03 Oct 2005
Posts: 88
Location: Ploiesti, Romania

View user's profile Send private message

The same old float printf problem
PostPosted: Wed Jan 31, 2007 3:52 pm     Reply with quote

I do the following with PCWH 4.023 :
Code:

float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;

printf(lcd_putc, "%9f", f1); // this shows -3.141500      Correct
printf(lcd_putc, "%9f", f2); // this shows -30.415000     Why 10 chars?
printf(lcd_putc, "%9f", f3); // this shows -301.150016    Now 11 chars?
printf(lcd_putc, "%9f", f4); // this shows 1280.467200    ??!?


I know CCS has big issues in this matter. I need to display floats with decimal point's position not being always the same. I could really use some help... I get the same results with 3.249 too.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 31, 2007 4:41 pm     Reply with quote

I think CCS must have only tested "%f" with very limited number of
width and precision values. The code below works. It displays this:
Quote:

-3.14150
-30.41500
-301.15000
-3014.50016

I did a few experiments and I think these might be the rules:
The "%f" format string is followed by "width.precision".
1. The width should be a maximum of 7.
2. The precision should always be at least 1 less than the width,
but no greater than 5.

For example "%f7.5" works. Also "%f4.3" works. Etc.

These rules are tentative. I didn't do a lot of testing on it.
I tested this with PCH vs. 4.023 (your version) in the MPLAB
simulator, with output going to UART1 (which is displayed in
the MPLAB output window).
Code:

#include <18F452.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

//====================================
void main()
{
float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;

printf("%7.5f \n", f1); 
printf("%7.5f \n", f2); 
printf("%7.5f \n", f3);
printf("%7.5f \n", f4); 
 
while(1);
}
VanHauser



Joined: 03 Oct 2005
Posts: 88
Location: Ploiesti, Romania

View user's profile Send private message

PostPosted: Wed Jan 31, 2007 5:39 pm     Reply with quote

PCM, thank you for your prompt reply, but there's another bug. When trying to print -30141.0 with "%7.5f" it shows 12808.67072 Sad

Honestly I don't know what try anymore. I just need to print a float made of at least 7 digits, let's say 9 chars together with the sign and decimal point. The bad news is that I can't predict where the decimal point will be, so the format must be a general one.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 31, 2007 7:24 pm     Reply with quote

Here is a possible alternate solution. Once, a long time ago, I was trying
to investigate the problems with the CCS floating point code. I studied
the .LST file and tried to understand the ASM code. I made some
progress but it was just too time-consuming and I gave up. I don't
even use floating point anyway.

During that time, I looked for other solutions and I found that a previous
forum member, Trampas Stern, had posted code on the MPLAB forum
that he said he found on the net. He had converted it to C18. I took that
code and converted it to CCS. It works. Using your test values,
posted earlier in this thread, here is the output of the program, which
shows the values displayed by the ftoa() routine, compared to the CCS
library code. In the first four tests, CCS is correct, but after that they
fail.
Code:

ftoa: -3.14150
 ccs: -3.14150

ftoa: -30.41500
 ccs: -30.41500

ftoa: -301.15001
 ccs: -301.15000

ftoa: -3014.50042
 ccs: -3014.50016

ftoa: -30141.50238
 ccs: 12808.17152

ftoa: -301415.02380
 ccs: -767.30372

ftoa: -3014150.23803
 ccs: -7672.95533

ftoa: -30141502.38037
 ccs: 9169.79254

Because the output of the ftoa() routine is placed in a string buffer,
you could take however many digits of it that you want, such as the
first nine digits as you said. You might have to write a little algorithm
to do this because if the number is negative, then the first character
will be the minus sign, etc., but it could be done.
The ftoa() routine is a little costly in terms of ROM usage. It takes
about 2300 bytes of ROM, when compiled with PCH vs. 4.023 for
an 18F452.

Here is the test program:
Code:

#include <18F452.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#include <stdlib.h>
#include <ftoa_ts.c>

//============================
void main()
{
float f;
char buffer[30];
char prec;
char format;

float f1 = -3.141500;
float f2 = -30.41500;
float f3 = -301.1500;
float f4 = -3014.500;
float f5 = -30141.50;
float f6 = -301415.0;
float f7 = -3014150.0;
float f8 = -30141500.0;

prec = 5;
format = 'f';


ftoa(f1, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f1);
printf("\n\r");

ftoa(f2, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f2);
printf("\n\r");

ftoa(f3, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f3);
printf("\n\r");

ftoa(f4, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f4);
printf("\n\r");

ftoa(f5, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f5);
printf("\n\r");

ftoa(f6, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f6);
printf("\n\r");

ftoa(f7, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f7);
printf("\n\r");

ftoa(f8, buffer, prec, format);
printf("ftoa: %s\n\r", buffer);
printf(" ccs: %7.5f\n\r", f8);
printf("\n\r");

while(1);
}


Here is the Trampas Stern code, converted to CCS:
Code:

//  FUNCTION: ftoa
//  AUTHOR = TRAMPAS STERN
//  FILE = strio.c
//  DATE = 2/6/2003  4:27:14 PM
//
//  PARAMETERS: long,*str, int count
//
//  DESCRIPTION: Convets an float to string
//     format 'f', 'E', or 'e'
//
//  RETURNS:
//
// NOTE this code was found on the web and modified
//  to actually work.
//-----------------------------------------------------------

int ftoa(float x, CHAR *str, char prec, char format)
{
int k, fstyle;

signed int8 ie, i, ndig;

//double y;
//float y;
   
CHAR *start;

start = str;

// Based on precision, set the number of digits.
ndig = prec + 1;

// if(prec < 0)
//    ndig = 7;

if(prec > 22)
   ndig = 23;

fstyle = 0;  // Exponent 'e'

if(format == 'f' || format == 'F')
   fstyle = 1;  // Normal 'f' style

if(format == 'g' || format == 'G')
   fstyle=2;

ie = 0;

// If x is negative, write minus sign and reverse.
if(x < 0)
  {
   *str++ = '-';
   x = -x;
  }

// If (x < 0.0) then increment by 10 until between 1.0 and 10.0.
if(x != 0.0)
  {
   while (x < 1.0)
     {
      x =x* 10.0;
      ie--;
     }
  }

// If x > 10 then let's shift it down.
while(x >= 10.0)
  {
   x = x * (1.0/10.0);
   ie++;
  }

/*
if(ABS(ie) > MAX_MANTISA)
  {
   if(fstyle==1)
     {
      fstyle=0;
      format='e';
      // ie=2;
     }
  }
*/

// In f format, the number of digits is related to size.

if(fstyle)
   ndig = ndig + ie;

if(prec == 0 && (ie > ndig) && fstyle)
  {
   ndig=ie;
  }


// Round. x is between 1 and 10 and ndig will be printed to
// the right of the decimal point so rounding is...
/*
y = 1;

for(i = 1; i < ndig; i++)  // Find least significant digit
    y = y * (1.0/10.0);    // Multiplying by 1/10 is faster
                           // than dividing

x = x + y * (1.0/2.0);     // Add rounding

// Repair rounding disasters.
if(x >= 10.0)
  {
   x = 1.0;
   ie++;
   ndig++;
  }
*/

// Check and see if the number is less than 1.0
if(fstyle && ie<0)
  {
   *str++ = '0';

   if(prec!=0)
      *str++ = '.';

   if(ndig < 0)
      ie = ie-ndig;  // Limit zeros if underflow

   for(i = -1; i > ie; i--)
       *str++ = '0';
  }


// For each digit.
for(i=0; i < ndig; i++)
   {
    float b;
    k = x;             // k = most significant digit
    *str++ = k + '0';  // Output the char representation

    if(((!fstyle && i==0) || (fstyle && i==ie)) && prec!=0)
       *str++ = '.';   // Output a decimal point

    b = (float)k;

    // Multiply by 10 before subtraction to remove
    // errors from limited number of bits in float.
    b = b*10.0;
    x = x*10.0;
    x = x - b;      // Subtract k from x

   // b=x+b;
   // x =x* 10.0;   // Get next digit
  }


// Now, in e style, put out the exponent if not zero.
if(!fstyle && (ie != 0))
  {
   *str++ = format;

   if(ie < 0)  // If number has a negative exponent
     {
      ie = -ie;
      *str++ = '-';
     }

   // Now we need to convert the exponent to a string.

   for(k = 1000; k > ie; k = k/10); // Find the decade of exponent

   for(   ; k > 0; k = k/10)
      {
       char t;
       t = DIV(ie, k);
       *str++ = t + '0';
       ie = ie -(t * k);
      }

  }
*str++ = '\0';
return (str - start);  // Return string length
}
VanHauser



Joined: 03 Oct 2005
Posts: 88
Location: Ploiesti, Romania

View user's profile Send private message

PostPosted: Thu Feb 01, 2007 6:03 am     Reply with quote

Thank you, PCM. Before seeing your post, I've came up with a simpler solution to my problem:
Code:
// Convert float to text, with max. 5 digits precision
// str should be at least 18 chars long
void float_to_text(float x, char *str) {
  int1 sign = 0;
  int32 whole;
  int32 frac;
 
  if (x<0) {
    sign = 1;
    x = -x;
  }

  whole = (int32)x;
  x = x - whole;
  x += 0.000001;  // eliminate precision problems
  x *= 100000;    // max. 5 decimal digits
  frac = (int32)x;

  if (sign) str[0] = '-';
  else str[0] = ' ';

  sprintf(&str[1], "%lu.%05lu", whole, frac);
}

I use this to display my floats in 8 char strings. It also gets rid of precision trouble. It takes 5...6 ms to execute @32Mhz. If I have some time, I'll test which is faster, my solution or yours. It's good to have it for future reference though.
VanHauser



Joined: 03 Oct 2005
Posts: 88
Location: Ploiesti, Romania

View user's profile Send private message

PostPosted: Fri Feb 02, 2007 9:51 am     Reply with quote

PCM, I have just tested the function you gave me, it works great and it is very fast, about 700 us execution time in my case. I will stick with it, thank you very much.
hadeelqasaimeh



Joined: 05 Jan 2006
Posts: 105

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 7:08 am     Reply with quote

hi pcm programmer
i try your code
it ok ,uptil some larg number,,it become wrong

here is my sample code:

Code:

#include <16f877a.h>
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#include "lcd_kbd1.c"

#include <stdlib.h>
#include <ftoa_ts.c>

//============================
void main()
{
float f;
char buffer[30];
char prec;
char format;

float f1 = 0;

      prec = 0;
      format = 'f';
      LCD_Init ( );
      LCD_PutCmd ( CLEAR_DISP );
    while (TRUE)
{
      ftoa(f1, buffer, prec, format);

      LCD_SetPosition ( LINE_16_1);//80-8f
      printf(LCD_PutChar,"%s\n\r",buffer);
      delay_ms(100);
      f1=f1 +1111;


}
}


i dont know why!!
hadeelqasaimeh



Joined: 05 Jan 2006
Posts: 105

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 7:11 am     Reply with quote

i wonder what do you mean by format ?? and which to choose!!

Quote:
format = 'f';
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 12:21 pm     Reply with quote

I tested it with compiler vs. 3.249 and it worked OK. However, I didn't
use an LCD. I displayed it with the MPLAB simulator with 'UART1'.
Here is the results, displayed in the Output window:
Quote:

0
1111
2222
3333
4444
5555
6666
7777
8888
9999
11110
12221
13332
14443
15554
16665
17776
18887
19998
21109
22220
23331
24442
etc.

So I think the ftoa() routine works OK.
hadeelqasaimeh



Joined: 05 Jan 2006
Posts: 105

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 4:29 pm     Reply with quote

hi pcm

i try to larger number,,my application suppose numbers of highr order
i will post them next;;
now if i i gnor this i try this code:

Code:

    value= READ_FLOAT_INT_EEPROM(address) ;
    ftoa(value, buffer, prec, format);

     strcat(S1,buffer);
     strcat(S1,S2);

     printf("%s",S1);
      //send msg to server


the value is incremented by a fixed step in an external routine,,but code suspend on it!!!and dont send any thing to RS232.

help plz
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 4:41 pm     Reply with quote

You didn't show any code. My guess is the S1 and S2 are not
initialized as strings. You probably left them as empty arrays.

Read my comments in this thread about "what is a string":
http://www.ccsinfo.com/forum/viewtopic.php?t=27630
hadeelqasaimeh



Joined: 05 Jan 2006
Posts: 105

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 5:45 pm     Reply with quote

thank for your fast reply

Code:


#include <16f877a.h>
#include <string.h>
#fuses xt,NOWDT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#byte tris_d =0x00
#define address  10    // Location in EEPROM

#include <stdlib.h>
#include <ftoa_ts.c>

void  WRITE_FLOAT_INT_EEPROM(long int , float );
float READ_FLOAT_INT_EEPROM(int ) ;






Code:

#int_ext
void ext_isr()  {

   value= READ_FLOAT_INT_EEPROM(address) ;
   value = value + 0.0003;
   WRITE_FLOAT_INT_EEPROM( address , value );
   ftoa(value, buffer, prec, format);

   output_high(PIN_A1);
   delay_ms(50);
   output_low(PIN_A1);

}

Code:


float value;
int cntr , cmd;
char buffer[30] ,S1[10],S2[10];
char prec;
char format;






Code:

      prec = 0;
      format = 'f';
      strcpy(S1,"*1$&");
      strcpy(S2,"#");



Code:
     value= READ_FLOAT_INT_EEPROM(address) ;
     ftoa(value, buffer, prec, format);

     strcat(S1,buffer);
     strcat(S1,S2);

     printf("%s",S1);
      //send msg to server

   }//  read



Code:

///////subroutine////////
void WRITE_FLOAT_INT_EEPROM(long int n, float data) {
   int i;

   for (i = 0; i < 4; i++)
      write_eeprom(i + n, *((int8*)&data + i) ) ;
}

//////////////////////////////////////////

float READ_FLOAT_INT_EEPROM(int n) {
   int i;
   float data;

   for (i = 0; i < 4; i++)
      *((int8*)&data + i) = read_eeprom(i + n);

   return(data);
}


//////////////////////////////////////





thank you again
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 5:47 pm     Reply with quote

What exact line does it lock-up on ?
hadeelqasaimeh



Joined: 05 Jan 2006
Posts: 105

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 5:51 pm     Reply with quote

Code:
    value= READ_FLOAT_INT_EEPROM(address) ;
    ftoa(value, buffer, prec, format);

     strcat(S1,buffer);
     strcat(S1,S2);

     printf("%s",S1);

this phrase
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 5:58 pm     Reply with quote

Add some putc() statements to determine which line it locks up on.
Run the program and watch the output in the terminal window on your PC.
Then post the results. This will tell us which line is causing the lockup.
Code:

putc('A');
    value= READ_FLOAT_INT_EEPROM(address) ;
putc('B');
    ftoa(value, buffer, prec, format);
putc('C');
     strcat(S1,buffer);
putc('D');
     strcat(S1,S2);
putc('E');
     printf("%s",S1);
putc('F');
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group