Hi, the following code for STM32F4 (Cortex-M4):
float fZero= 0.; float fInfinity; short sTestPlus, sTestNeg; int main( void){ fInfinity= 1.f/fZero; sTestPlus= fInfinity; fInfinity= -1.f/fZero; sTestNeg= fInfinity; while(1); }
should result in the values sTestPlus= 0x7FFF and sTestNeg= 0x8000. Instead it produces 0xFFFF and 0x0000.
The reason is, that the compiler uses the signed 32bit convert (leading to the correct result 0x7FFFFFFF and 0x80000000), and then just cuts out the lower short, which is really poor.
As I understand, it is no problem with Cortex M4 to do float to signed16 using the VCVT command in a more sophisticated way (specifying 16bit).
Is there a way to get this done?
should result in the values sTestPlus= 0x7FFF and sTestNeg= 0x8000.
No. There are no particular values these should result in. Conversions from floating-point to integer that would yield out-of-range values cause undefined behaviour (C99 6.3.1.4p1)
So no matter what you expect this to yield, that expectation is wrong.
For int32 the VCVT function used does exactly what I would expect: -inf gives 0x80000000 and +inf gives 0x7FFFFFFF.
This is a well defined behaviour, and also very useful. The VCVT command takes only 1 cycle. If together with every VCVT I would have to check for such infinity cases, I would spoil about 5-20 further cycles - this would blow up the code quite appreciably.
Generally, including +-INF into the number range is a very big benefit if floating point calcualations are done. It was a major point in introduction of the IEEE floating point stardard to define a clear behaviour of such INF values in several situations. This then of course also requires a sound convert to fix point.
The Cortex M4 Generic User Guide shows, that float to fix convert is handled by Cortex M4 very carefully - it has very careful options:
VCVT{cond}.Td.F32 Sd, Sd, #fbits VCVT{cond}.F32.Td Sd, Sd, #fbits
Td can be S16, U16, S32, U32. To my tests, the compiler currently uses only S32 and U32, but for short/int16 variables this is not very helpful - then you get illegal results as soon as the floating point value is above the number range - which of course easily can happen, especially for short/int16. Creating such illegal results from my point of view is a compiler error.
Further there is this nice possibility of "fbits" - this additionally can be very useful to restrict the number range further. I did not find any possibility in the help file, how to use this command efficiently from the C compiler - as there is also no inline assembler available for STM32F4, I do not come further at this point. From my point of view, it would be very useful to create an intrinsic function for this powerful command.
PS: Mike, I only use the division by zero to get these infinity values in the floating point registers - you could possibly also use other methods. (but I do not really understand your posts ...).
but I do not really understand your posts
My point is that the behavior of your code isn't defined by the C standard. It's not defined by the compiler reference manual either, as far as I can see. You may have found some compiler features that can be used in your code. But since you are relying on undocumented behaviour, you'll have to verify that the undocumented features are still there every time you upgrade the compiler or use a different library (microlib?) or make other significant changes to you build environment.
But conversion from int to float is nothing mystical - why should this be not documented?
At least - if I should be able to use Cortex M4 efficiently, it would be necessary that there is some inline/intrinsic possibility to use this VCVT command with its full power.
Well, I don't know. Why don't you ask Keil? It's their documentation, after all. Or maybe I didn't dig deep enough.
Definitely. Sounds like a feature request that should be directed to Keil.
But conversion from int to float is nothing mystical
It's also not not what we've been talking about here. That was float-to-int, not int-to-float.
- why should this be not documented?
Why should it be? Per the language definition your code causes undefined behaviour. That means the compiler itself can crash, or generate code that returns a different, random number every time, and still be 100% correct, without the need to document anything.
Yes, ARM could have decided to define a particular behaviour in this cause, and maybe they did. In that case, and only then, they should have documented this decision. But the fact that nobody seems to have found any such documentation would seem to indicate that no such decision was made.
Summary: this code is buggy. It relies on unwarranted assumptions. For the ARM compiler, these assumptions actually are incorrect, so the bug became noticeable.
This is a well defined behaviour
So you think. But who, do you think, defined it? And who put them in the position to be defininig such things?
then you get illegal results as soon as the floating point value is above the number range
You've been told several times already that this assessment is incorrect. No, those results are not illegal. They're not even wrong. They're well inside the allowed range of results --- because by definition of the C programming langauge, that range is infinite. The only thing wrong here is your belief that you know what the result should be.
The infinite value is not the crucial thing here - perhaps I was a bit to radical in my first code snippet - very sorry.
You will get the same illegal behaviour of float to int16 (of course float to int - thank you for pointing this out), if you take any number above the int16 range. You could e. g. write the following:
float f1= 65537.; float f2= -65538.; short s1, s2; int main( void){ s1= f1; s2= f2; while( 1){} }
Now s1 ends up as 0x0001 (because 65537= 0x10001) and s2 as 0xFFFE (because -65538= 0xFFFEFFFE).
This is neither correct nor makes much sense.
I would possibly accept such behaviour, if the processor would have no intrinsic command to convert float to int16, but in this case of Cortex M4 this is clearly not acceptable (from my point of view ...). (as there is a nice command to convert float to int16).
You still talk in terms of "illegal behaviour" for something the language standard specifically calls "undefined". Your personal views can't just be updated into hard laws for the compiler vendors to follow.
View all questions in Keil forum