Comparison between floats and constants doesn't work, CW10

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Comparison between floats and constants doesn't work, CW10

1,704 Views
done78
Contributor I

Hello,

I've come across this problem writing code for MC9s08QE128 MCU: if i want to test a float to be greater than zero and write something like this:

 

 

double a;a = -150.1;if(a>0) {    //do action 1;} else {  //do action 2;} ....

 

 

well, it does ACTION 1 !! how can it be ?

I' have also tried

 

if(a>0.0) 

 

and

 

if (a>(double)0)... but it doesnt work ! Strange thing is that instead

 

 

double a;a = -150.1;if(a>0.1) {   //do action 1} else {   //do action 2}

 

 

works correctly !!!

Am I missing something ? I have got float support on my project (ansifs.lib included) and using small memory model.

Thank You for your help !

Labels (1)
Tags (1)
0 Kudos
9 Replies

855 Views
bigmac
Specialist III

Hello,

 

I suspect the problem is related to the fact that zero is not  within the normal floating point numeric range, and requires a special floating point representation.  I do not know how the compiler is supposed to behave under these circumstances, but the work around may be to compare with a very small, non-zero value ( e.g. 1E-300 for a double).

 

Were there any warnings during compile?

 

Regards,

Mac

 

0 Kudos

855 Views
CompilerGuru
NXP Employee
NXP Employee

I don't consider 0 to be that special as floating point value, would hope every compiler supporting floating point supports comparison with 0.

 

I suspect it is either a project setup issue like using the 32 bit float library as mentioned without using -Fd, so the compiler thinks double are 64 bit but the runtime library reads them as 32 bit, or some other setup issue.

Another possibility is that other optimizations make the wrong impression that the if part gets executed when actual the else is. Are you sure the else part really gets executed? It may just look like that.

Often if and else clauses end with the same code, so branch tail merging (-onb=t, -onbt) share the code causing unexpected stepping in the debugger.

 

Either way, please generate a new project with the wizard copy the code into it and try to reproduce it.

I did try that, and in the shown setup the compiler does not even generate code for the if but issues a warning the if part is dead code (which it is). So I guess the actual sample looks a bit different, the variable is not just always negative. Please provide a full compilable sample project.

 

Daniel

0 Kudos

855 Views
Lundin
Senior Contributor IV

It is easy to verify if Daniel is on the right track by trying

 

if((float)a > 0f)

 

If the above code works, then it seems likely indeed that the project setup is broken somehow.

 

The f means that the numeric constant is explicitly a float (same thing as casting (float)0.0). While 0.0 is always treated as a double. For future reference, you don't need to do the explicit typecasts to double, since the C standard guarantees that any operation between a double and another number, will implicitly convert the other number to double as well. This is well-defined by something in the standard called "the usual arithmetic conversions":

http://msdn.microsoft.com/en-us/library/3t4w2bkb(VS.80).aspx

 

0 Kudos

855 Views
CompilerGuru
NXP Employee
NXP Employee

Using a float comparison does not actually help if the compiler and the library are using a different size for double, if the compiler thinks double is 64 bit, he will insert a double to float conversion before comparing with 0.

Anyway, improper setup are one usual suspect when floating point operations do not work properly. Another usual suspect, not sure if it is the case here, is stack overflow. The floating point routines, especially the 64 bit ones use quite a bit of stack.

In the end as the OP did see something strange happening in his code, reproducing the setup in a new project is one way to narrow it down. If it happens with a shareable project, we can have a look. 

 

Daniel

 

0 Kudos

855 Views
Emac
Contributor III

This looks like a simple (classic) programming mistake that crops up in C due to weak type cast checking.  Many have made the same mistake (myself included).  The program is interpreting the 0 (try 1 for that matter) as an INTEGER.

 

Good programming practice is to either always include decimals for floats;  0 should be written as 0.0 and 1 should be written as 1.0 (etc) or better yet append ansii type standards to the value such as 0.0f and 1.0f for floats or 0.0L for a double.

 

 

 

0 Kudos

855 Views
Lundin
Senior Contributor IV

No it is not interpreting it as an integer, read the link I posted about "the usual arithmetic conversions". Very fundamental knowledge.

 

0 Kudos

855 Views
Emac
Contributor III

All good stuff Lundin.  Also didn't know that about about the double. 

 

I don't think that you can always assume correct "standard" implemntation of C though, and Microsoft, by any means, can't be considered the ultimate authority as they are just as quick to break the rules and make their own as the next guy...

 

I have found (shockingly) that there are times when the freescale compiler does stuff you don't normaly see (for example the testing of bit values and true vs. false vs. 0 vs. 0xfffffff

 

That said, looking back, I don't think we helped this guy yet.

 

He has done all the standard - good stuff -by testing it and even trying 0.0 but getting false results.

 

  • The only thing we haven't told him to try is by using +0.0 or -0.0 or by using the ieee definition of zero  (32 bit)( 0x0000 0000) instead which should totally solve his problem if the first two don't work.

 

He may have also oversimplified his example:

 

  • Has anyone asked if he is using a global (or external)  (variable a) and has the optimizations turned on (default)?

It could simply be if he doesn't change the variable within the scope of his test and the optimizer optimized it out (since he doesn't change the value here).

 

  • Also, Done78, have you looked at the disassembly to verify that your test case 2 is even compiling?

You might have the warning "Removed Dead Code" which could clue you in to some undesired effects of optimization.  You could also run by setting optimization to zero ( adding -O0 to the compile settings - thats an "Oh" Zero) or using the optimizations tab and selecting "disable optimizations"

 

Good luck, I hope this helps.  Sorry I didn't read your earlier post about trying 0.0 with no luck.

 

 

 

 

0 Kudos

855 Views
Lundin
Senior Contributor IV

> I don't think that you can always assume correct "standard" implemntation of C though

 

No you can't, which is very sad, and it's entirely the compiler industry's fault. No matter, it is the engineer's job to pick a compliant C compiler, and document all non-standard behavior affecting the program.

 

> and Microsoft, by any means, can't be considered the ultimate authority

 

No of course not. But that Microsoft text happens to be a mere copy/paste of the C standard. Check ISO 9899:1999 6.3.1.8 and find the very same text. The usual arithmetic conversions is one of the few things in the C language that is consistently implemented according to the C standard across various compilers.

0 Kudos

855 Views
CompilerGuru
NXP Employee
NXP Employee

If you compare an int with a double, the int is automatically converted to a double, so I don't think this is the issue of the original poster.

Where the suffix matters is mostly when using floats, without a f suffic, all constants are doubles so

 

float a,b; a = b * 1.1;

 

is compiled as

 

a = (float)((double)b * 1.1);

 

which just slows the computation down without helping with precision.

It is better written as:

 

a = b * 1.1f;

 

Daniel

 

BTW: 0.0L is a long double, for a double just write 0.0 (no special suffix).

0 Kudos