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.
View all questions in Keil forum