float math warning...

Beta Testing discussion on mikroC PRO for AVR.
Post Reply
Author
Message
sadavis80
Posts: 114
Joined: 15 Nov 2008 19:27

float math warning...

#1 Post by sadavis80 » 23 Nov 2008 03:24

If you have code such as

Code: Select all

double f; int i, k;
 i = 92;
 f = 360 * i/256;  // convert 0..255 to 0..360
Something happens that you won't like. The '360' apparently causes a 'cast' of the int to a unsigned char (or something like that) and 'de'motes the math to byte math - thereby causing this particular iteration to become NEGATIVE.

A simple change of '360' to '360.0' fixes everything - provides proper promotion of whatever is the problem - and it gives the correct result - at least according to the debugger :).

I seem to remember seeing this issue in other C compilers before, but my brain is fading ...

There's probably a REASON that I'm just not aware of .. but a warning non the less :?.

Steve

David Prentice
Posts: 8
Joined: 30 Oct 2008 12:23

#2 Post by David Prentice » 23 Nov 2008 14:58

Your example is going to fail with ANY int16_t compiler.

e.g. 360 * 92 = -32416 ( a negative number )

and -32416 / 256 = -126.625 or -127


You should ensure the correct operation with suitable casts. It is more efficient to cast the LH operator as a long ( signed or unsigned ) to ensure that correct maths is done. Obviously you can ensure a float operation if you really want to.

You could possibly cast as a uint16_t but I would be wary.

David.

sadavis80
Posts: 114
Joined: 15 Nov 2008 19:27

#3 Post by sadavis80 » 23 Nov 2008 15:35

Thanks David. I did uC programming 'way back when' - well before the fancy new IDE compilers of today existed :). I understand a lot of the underlying stuff, but maybe not so much as I need of the new compiler technology.

For my benefit... Why would using a cast be more efficient than putting the '.0' in there and letting the compiler do the cast internally?
tia,
Steve

David Prentice
Posts: 8
Joined: 30 Oct 2008 12:23

#4 Post by David Prentice » 23 Nov 2008 16:33

int f = 360L * i / 256; // will calculate the result in long and then assign to int
int f = 360.0 * i / 256; // will calculate everything in floats and then truncate it back to an int16_t

These two examples show implicit casts. A more conventional cast would be:
int f = (long)360 * i / 256; // will calculate the result in long and then assign to int

it can be VERY handy to scale an integer with a float constant. This ensures that you lose nothing in the truncation. In fact it rather looks as if you want to scale i by 1.40625

The int32_t Math will be a lot shorter code and quicker execution. However it seldom matters unless you are inside an ISR.

David.

sadavis80
Posts: 114
Joined: 15 Nov 2008 19:27

#5 Post by sadavis80 » 23 Nov 2008 16:39

Thanks for the info. Yes - I'm scaling a 0..255 output to a desired 0..359 - and this code *IS* done in initialization. I used the float method because I don't want to TRUNCATE - I want to ROUND (and I wrote code to do that).
I try to avoid ANY math if at all possible in my ISR (and this DOES use the resultant array in an ISR).
Steve

Post Reply

Return to “mikroC PRO for AVR Beta Testing”