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

To Float or not to float?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

To Float or not to float?
PostPosted: Fri Jul 01, 2011 3:50 am     Reply with quote

Assumption: in the code I always use RAW unsigned int values when working with sensors.

All right so, floats operations are really handy to display some neat data on the LCD, float is the format of values from sensors, floats give those juicy right comma placed numbers and it's a joy to waste countless days to fine tune them, filters, smooth, numeric tricks...

..but float operations are so slooooww and once inserted in the code, they simply make it's size/execution explode istantly!

So, I'm trying to avoid them at all costs.

In my code I had:

Code:
printf(lcd_putc,"Batt:%2.1fC ", (float)val_temp()/16.41153191);


Where val_temp() is the output in unsigned int16 of a reading from a LM35 (already with an OPAMP to amplify it's excursion) - and that magic number 16.41153191 is the scale ration.

I tryied to "optimize" this thingh and come up with:

Code:
printf(lcd_putc,"Batt:%2.0wC ", (val_temp()*15)/246);


Where, *15 is overflow safe (1023*15<65k) and /246 yelds a total resize of 16,4.

Precision is "quite" ok, I could fine tune it more: I could increase the *15 and choose a new division factor which could get more near the original value.

What if I want a decimal place? I would need to get from the division a x10 number, so I could put a . with:

Code:
printf(lcd_putc,"Batt:%3.1wC ", (val_temp()*150)/246);


But then I should use an int32 at least, because val_temp()*150 will overflow :\

What do you suggest, is my approach accepltable, are there other clever ways to save space?

P.S. Saving space in the code area of the PIC is the first issue, speed is secondary.
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 5:42 am     Reply with quote

quick comment

Stick with integer math.

I've used thousands of the LM35/LM34s over the past 2 decades and no 2 are identical,same holds true for the gain of op amps, so really unless this is a 'one off' project you're just playing with numbers for the sake of numbers.No amount of 'clever math tricks' will get two boards to be the same.
Reality is that if the sensor reads 20*C that's fine to us humans. 19.99996 or 20.123456 is NOT important.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 6:22 am     Reply with quote

If val_temp is coming from an A/D reading your LM35 you probably aren't getting more than 12 bits, and in most applications 8 bits will do fine. Properly scaled 8 bits gives better than 0.5% resolution.

I have used floats for occasional debug. But I don't think I have ever used floats in actual final code shipped to a customer.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 7:38 am     Reply with quote

and some more comments:

Float's are _not_ the 'format of values from sensors'. Numbers arriving from sensors will always be integers

Think for a moment about things like DVM's. _scaled integers_ are what they display.

Digital filters commonly use scaled integers as well.

Anything requiring repeatable precision avoids float's at all costs (look at financial calculations for example).

Now, yes, your approach is a start. However you need 'L' in the %w declaration.
Then remember that float on the PIC16/18, only handles at best 6.5 decimal digits. The last four digits in your constant in the original value were doing nothing. You hardware is unlikely to be doing better than 0.1% accuracy anyway, so 90% of the values being displayed by the float, are 'fallacious'...
Remember also division is always slower than multiplication (except for constant using a binary value - 2,4 etc.).
So start by reciprocating your value.
*0.609327, would immediately be several times faster.
Now remembering the comment about binary divisions, multiply by 256
So:
Code:

printf(lcd_putc,"Batt:%3.1LwC ", ((int32()val_temp())*1560)/256);


Potentially four digits of accuracy (0.6093*), and probably about 10* faster.

Best Wishes
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 9:34 am     Reply with quote

temtronic wrote:
quik comment

Stick with integer math.

I've used thousands of the LM35/LM34s over the past 2 decades and no 2 are identical,same holds true for the gain of op amps, so really unless this is a 'one off' project you're just playing with numbers for the sake of numbers.No amount of 'clever math tricks' will get two boards to be the same.
Reality is that if the sensor reads 20*C that's fine to us humans. 19.99996 or 20.123456 is NOT important.


Agree! the LM35 is rated +/-0.5C accuracy already.
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 9:36 am     Reply with quote

Ttelmah wrote:
and some more comments:

Float's are _not_ the 'format of values from sensors'. Numbers arriving from sensors will always be integers

Best Wishes


Right, but I was viewing a sensor from end user: anything "measured" should be a number with a scale (speed, weight, lenghts, temp, etc..).

So, floats, or, a number with a meaningfull "point" is the objective ;)
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 10:01 am     Reply with quote

Ttelmah wrote:
and some more comments:

*0.609327, would immediately be several times faster.
Now remembering the comment about binary divisions, multiply by 256
So:
Code:

printf(lcd_putc,"Batt:%3.1LwC ", ((int32()val_temp())*1560)/256);


Potentially four digits of accuracy (0.6093*), and probably about 10* faster.

Best Wishes


You are Right!! try to divide always by a multiple of 64 :)

In the end I did this:

Code:
printf(lcd_putc,"Batt:%3.1wC ", (val_temp()*39)/64);


That is giving a 3 places integer number which I display with one decimal place. No overflow, "accuracy" is ok/good; no int32 and I save another 3% in code size (using a PIC16F690).

Thanks for the usefull suggestions to all!
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 10:07 am     Reply with quote

SherpaDoug wrote:
If val_temp is coming from an A/D reading your LM35 you probably aren't getting more than 12 bits, and in most applications 8 bits will do fine. Properly scaled 8 bits gives better than 0.5% resolution.


Right! in fact, diving by 64 (see post above) is just doing the trick.

Anyway, it's just a home project, I'm building a sort of Lion (whatever the chemistry) battery charger, and I'm using an LM35 near the battery to sample the temperature, I just needed a meaningfull .1 temp. reading so I could "see" is the battery was going to overheat or not (visual inspection).
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 10:11 am     Reply with quote

Consider the difference between floats and fixed point numbers. You can calculate integer millidegrees much faster than you can true floats, and use %w to put the decimal where it belongs for display. The idea is that for most real world values the decimal point really doesn't need to float at all. If a thermometer is going to display 6.5 degrees, or 65.4 degrees or 654.3 degrees, the decimal does not move.
_________________
The search for better is endless. Instead simply find very good and get the job done.
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 3:40 pm     Reply with quote

SherpaDoug wrote:
Consider the difference between floats and fixed point numbers. You can calculate integer millidegrees much faster than you can true floats, and use %w to put the decimal where it belongs for display. The idea is that for most real world values the decimal point really doesn't need to float at all. If a thermometer is going to display 6.5 degrees, or 65.4 degrees or 654.3 degrees, the decimal does not move.


Totally agree!
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sat Jul 02, 2011 2:17 am     Reply with quote

Glad you have worked out a solution that suits.

It might be quite 'informative', to just run this part of the code in MPLAB simulator, and time it. The division by 64, should only take perhaps a dozen machine cycles now, and the multiplication perhaps a couple of hundred cycles. Also the actual output in printf, will also be faster. The %w format, is only having to divide by ten in integer, for each digit, versus the %f version is having to do a float division for each digit.
I'd be expecting something around 10* speed gain. Smile

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Jul 02, 2011 2:52 am     Reply with quote

Digital signal processing of sensor data partly requires complex arithmetic, e.g. applying higher order polynomials or exponential functions. Although everyhing can be done in integer fixed point with respective coding effort, these calculations are an obvious domain of float arithmetic.

If lower speed and slightly higher code size aren't an issue, you can expect faster project completion and less hidden faults utilizing float, if complex calculations are involved.
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

PostPosted: Sat Jul 02, 2011 3:46 pm     Reply with quote

Ttelmah wrote:
Glad you have worked out a solution that suits.

It might be quite 'informative', to just run this part of the code in MPLAB simulator, and time it. The division by 64, should only take perhaps a dozen machine cycles now, and the multiplication perhaps a couple of hundred cycles. Also the actual output in printf, will also be faster. The %w format, is only having to divide by ten in integer, for each digit, versus the %f version is having to do a float division for each digit.
I'd be expecting something around 10* speed gain. :)

Best Wishes


I'm trying to get a rough value about the code speed, I've opened a thread on the matter a couple of days before (or less, at the bottom the link to it).

To get the execution time of some instruction, I'm doing this way:

Code:
enable_interrupts(int_TIMER1);   
      leap=0;
      set_timer1(0);
                         
        // Code to analyze         
        lcd_gotoxy(1,1);
        printf(lcd_putc,"%Lu", (val_volt()*30)/61);
        // ends here

      v1=get_timer1();
      disable_interrupts(int_TIMER1);
      printf(lcd_putc,"\f%Lu, %u", v1,leap);


If timer1 overflows, it just increments leap; TIMER1 is set as divide_by_1. So, basically, I'm making the PIC displays the increments made by timer1 - with a 8MHz clock, I get 0.5us resolution, nice and effective :)

(can you confirm to be correct too?)

http://www.ccsinfo.com/forum/viewtopic.php?t=45729 - this is the thread were I'll post the same code, to keep things in order, I'll keep posting about the general code speed issues there ;)
_________________
Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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