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

Math question
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
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

View user's profile Send private message Send e-mail

Math question
PostPosted: Fri Mar 24, 2017 6:56 pm     Reply with quote

CCS PCH C Compiler, Version 5.059, 31220
PIC18F26K22
Code:
#use delay(internal=64MHz)

As I would like to have any math operation in less than 1us, I made the below test and got the out-commented times.
Code:
int a=250;
int b=2;
long c=250;
a=250;//0.0625us
a=a/2;//0.125us
a=250;//0.125us
a=a/b;//6.25us
c=250;//0.25us
c=c/2;//0.1875us
c=250;//0.125us
c=c/b;//21us
delay_cycles(1);

Tried also with #include "math.h", same results, even worse.
How can be so big differences while dividing by 2 and dividing by an 8 bit int?
Also how can be that moving a literal to a long in one case takes 0.25us and other case 0.125us?

Best wishes
Joe
newguy



Joined: 24 Jun 2004
Posts: 1907

View user's profile Send private message

PostPosted: Fri Mar 24, 2017 7:10 pm     Reply with quote

Dividing by two is the same as doing a binary shift right by 1. Binary shifts are fast. Actual division is slow. There is no way around the long divide times.

For fun, repeat your exercise using floats.
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

View user's profile Send private message Send e-mail

PostPosted: Fri Mar 24, 2017 7:34 pm     Reply with quote

Thanks for the reply Newguy.

Started with floats, as my program was using floats.
I am getting in the range of 70us.
Changed to *;/;+;-;. Not perfect, but acceptable.

One more question:
I am using floats in an other part of the program that it will be much more difficult to replace with simple math.
If an interrupt occur while performing a so long calculation it will be served immediately or just after the calculation is finished?

Best wishes
Joe
temtronic



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

View user's profile Send private message

PostPosted: Sat Mar 25, 2017 5:35 am     Reply with quote

Yes, 'floats are fun' with a PIC ! Unless absolutely necessary, avoid them, use scaled integers...binary divisors(2,4,8,32), etc.

Re: Interrupts. Generally speaking PICs will complete the current machine code instruction they are executing (not an equation !), 'service' the interrupt, then return to where it left off and carry on. CCS adds code to make the operation 'tidy'.
Depending on your level of expertise and knowledge of PICs, stack, variables and what you need it to do, you can modify the CCS ISR or cut your own. For time sensitve code, this can help BUT change stuff down the road, and it might crash on you.....

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Sat Mar 25, 2017 5:51 am     Reply with quote

Immediately, unless for some reason interrupts are disabled.

This is where 'scaled integers' come in very useful.

Have a look in the manual 'common questions and answers'. 'How much time do maths operations take'.

For instance, suppose I want to divide by three.

Assume an int8 value, stored in an int16.

Now
value/3 will take about 20uSec.

(value*85), and then just read the high byte of the result, will take about 2uSec!...

Similarly if I want to print a number from an ADC reading as 0.00 to 5.00v. Assume reading is 10bit (0 to 1023).
Each step of the ADC is 0.0048828v.

Now three different solutions:

First just take the ADC reading, change to float, multiply by 5.0, divide by 1024.0, and print as a float. Slowest solution. The compiler will presolve partially but may well still divide by 204.8. This will take about 110uSec, then it'll have to do floating point divisions by 10.0 for each digit to output. So for three actual digits, perhaps 440uSec.

Second just use *0.0048828. Potentially a little faster. Multiplication is typically about 4* faster than division, but it still has to use /10.0 for each digit. So perhaps 350uSec.

Third use integers:
Take ADC_reading. Put into an int32. Multiply by 32000. Now just read the high 16bits of this (so effectively /65536, but involving no maths at all). Total time to do this, about 16uSec. Now print this 16bit value using %4.2LW. Uses 16bit integer divisions. About 76uSec total.
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

View user's profile Send private message Send e-mail

PostPosted: Sun Mar 26, 2017 1:21 pm     Reply with quote

Thank you for the answer Ttelmah and Jay

When testing in MPLAB simulator during long calculations the cursor jumping to the controller header file.
Can't see what is doing there but if an interrupt will occur during this time and it will be served immediately I can afford that.

Best wishes
Joe
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Sun Mar 26, 2017 1:24 pm     Reply with quote

If you remark out the entry '#NOLIST' that is at the start of the include file for the processor, then re-compile, the code for the maths routines will be included, so you can see how this is done.
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

View user's profile Send private message Send e-mail

PostPosted: Sun Mar 26, 2017 3:36 pm     Reply with quote

Thanks Ttelmah

I see the math, very complicated.
I am trying to rewrite the functions not to use float and break down the calculations to keep all below 1us.

Best wishes
Joe
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Mon Mar 27, 2017 2:24 am     Reply with quote

1uSec. Probably not going to happen...
Even at 64MHz, that is only 16 machine instructions. Even if you solved everything just using (for example) a lookup table, just loading the values, and reading the result would take longer than this...

Aim for something like 10uSec, and with ingenuity, this may well be doable.

Division is always the slowest basic maths operation. Your chip has hardware to do an integer multiply, but nothing similar for a divide.

Maths.h, should not change anything.
Functions are not actually included in the code, unless they are _used_. Maths.h, supplies functions for things like sin, cos, log etc.. Simple */+-, are part of the core compiler and do not want/use maths.h.

One trick I commonly use, is to remember that for an integer, division by 256, or 65536, can be done by just throwing away the bottom byte or bottom pair of bytes. So I've done (for example) fast PID maths by using an int24 (I coded a library for this), storing the PID factors as if they were integer 'two fifty sixths', instead of fractions, and then just taking the upper 16bits of the results.
uzicarl



Joined: 28 Mar 2017
Posts: 1
Location: Banned - spammer

View user's profile Send private message Visit poster's website

PostPosted: Tue Mar 28, 2017 12:40 pm     Reply with quote

hi! I don't think you can avoid floats. I know that binary is fast but floats are necessary
_________________
CA-banned-RL
newguy



Joined: 24 Jun 2004
Posts: 1907

View user's profile Send private message

PostPosted: Tue Mar 28, 2017 1:33 pm     Reply with quote

uzicarl wrote:
hi! I don't think you can avoid floats. I know that binary is fast but floats are necessary


For angles, cos, sin, tan, etc.: maybe. For anything else, definitely not. You can accomplish the same thing using scaled integers much more quickly and with less memory usage.

Quite some time ago the dept's software engineer was responsible for taking GPS data and plotting locations on a map to determine the distance between locations. The data was made available on our internal CAN bus via a special module that interfaced to a GPS receiver. When he started calculating his distances, he was getting values on the order of a few hundred meters for points that were only 1 or 2 meters apart.

Turns out he was first casting the raw GPS data to a float, then using those floats in his calculations. Anyone who had (or still has) an HP calculator knows that, sometimes, when you enter a number the calculator will display that number with ".000000000001" added to it. When you're trying to pinpoint locations on the surface of the earth, that little bit of error really hurts you in the end. I told him to not cast the raw data to a float and try again. Turns out he then started getting numbers about what we were expecting.
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

PostPosted: Tue Mar 28, 2017 2:15 pm     Reply with quote

Sin's and cos can often avoid floats (binary scaled integers instead). The only thing I've has to use float for in about the last 10 years on a PIC, was when writing a logarithmic value.

It's worth understanding that people like NASA don't generally use floats. Nor do bankers. For both, the errors are too large, and they 'know' the maths ranges involved, so use fixed point arithmetic instead.
temtronic



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

View user's profile Send private message

PostPosted: Tue Mar 28, 2017 3:20 pm     Reply with quote

Also... the CCS floating point isn't really good past what 4, 5 places? and of course the PIC wasn't designed for FP a zillion years ago.
Now if you added an external FPU...........

Jay
gjs_rsdi



Joined: 06 Feb 2006
Posts: 468
Location: Bali

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 29, 2017 4:34 am     Reply with quote

Thank you all for the answers.

We had here in Bali the yearly "Silence day" were everything is silent, no traffic, no lights, I was out from Internet.
One of the functions is done already with simple maths, all divisions by 2, 4, 8 and multiplications by numbers from 1 to 15. Using also + & -.
Non passes 0.5 us Smile
Remain three to complete, hope will succeed.

In another program for navigation I am using sin, cos, etc but the microcontroller doesn't have any time critical functions so floats are fine.

Again thank you for the help.
Joe
Marttyn



Joined: 06 Mar 2015
Posts: 28
Location: Spain

View user's profile Send private message Visit poster's website

PostPosted: Wed Apr 15, 2020 3:24 pm     Reply with quote

Ttelmah wrote:
Immediately, unless for some reason interrupts are disabled.

This is where 'scaled integers' come in very useful.

Have a look in the manual 'common questions and answers'. 'How much time do maths operations take'.

For instance, suppose I want to divide by three.

Assume an int8 value, stored in an int16.

Now
value/3 will take about 20uSec.

(value*85), and then just read the high byte of the result, will take about 2uSec!...

Similarly if I want to print a number from an ADC reading as 0.00 to 5.00v. Assume reading is 10bit (0 to 1023).
Each step of the ADC is 0.0048828v.

Now three different solutions:

First just take the ADC reading, change to float, multiply by 5.0, divide by 1024.0, and print as a float. Slowest solution. The compiler will presolve partially but may well still divide by 204.8. This will take about 110uSec, then it'll have to do floating point divisions by 10.0 for each digit to output. So for three actual digits, perhaps 440uSec.

Second just use *0.0048828. Potentially a little faster. Multiplication is typically about 4* faster than division, but it still has to use /10.0 for each digit. So perhaps 350uSec.

Third use integers:
Take ADC_reading. Put into an int32. Multiply by 32000. Now just read the high 16bits of this (so effectively /65536, but involving no maths at all). Total time to do this, about 16uSec. Now print this 16bit value using %4.2LW. Uses 16bit integer divisions. About 76uSec total.


Ttelmah, just amazing!
Can you share a little bit more of your knowledge? Specially how to "twist" the maths to make them more fast and efficient.
I, understand the first example, where you have:
result = value / 3
The same as:
result * 256 = value / 3 * 256
result * 256 = value * 85 <--- 256/3
result >> 8
well... more or less, but this is the core...
But don't understand the last example... why you multiply by 32000?

And can you show some more examples? or is there any good resource to find examples like this? Would like to learn to think "that way" Smile
Thanks!
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