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 !
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
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
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
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
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.
No it is not interpreting it as an integer, read the link I posted about "the usual arithmetic conversions". Very fundamental knowledge.
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.
He may have also oversimplified his example:
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).
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.
> 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.
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).