Discussion:
Floating point in printf() functions
Sundberg, Ryan
2012-11-29 00:05:30 UTC
Permalink
Hi Guys,

I'm noticing a bug with snprintf floating point strings for values > 1000, but only when compiled with -mfloat-abi=hard (on an stm32f4 arch)
The change log for 6.23 indicates some recent float fixes for printf functions.


nsh> float_test

str(%d): '40017' [ with value casted to int ]

str(%f): '0X017'

str(%.0f): '0X017'

str(%.4f): '0X017.0000'





When compiled with mfloat-abi=softfp, it works as expected. There are no compiler warnings that I'm ignoring.

Anyone have a clue?


Thanks,
Ryan Sundberg
Michael Smith
2012-11-29 06:23:32 UTC
Permalink
Ryan,

You might want to try a simple test to see whether there is an issue with varargs and floating point numbers.

Another option would be to try calling printf with a format string and matching arguments that contains at least 10 floating point numbers (because my cursory reading of AAPCS doesn't convince me that the compiler might not use all of d0-d7 for arguments - you might want to check the generated assembly).

If the last number is printed correctly, that would point the finger fairly squarely at a varargs / stdarg.h issue.

= Mike
Post by Sundberg, Ryan
Hi Guys,
I’m noticing a bug with snprintf floating point strings for values > 1000, but only when compiled with –mfloat-abi=hard (on an stm32f4 arch)
The change log for 6.23 indicates some recent float fixes for printf functions.
nsh> float_test
str(%d): '40017' [ with value casted to int ]
str(%f): '0X017'
str(%.0f): '0X017'
str(%.4f): '0X017.0000'
When compiled with mfloat-abi=softfp, it works as expected. There are no compiler warnings that I’m ignoring.
Anyone have a clue?
Thanks,
Ryan Sundberg
Sundberg, Ryan
2012-11-29 19:59:03 UTC
Permalink
That didn't work out - the issue is within dtoa(), my debugger shows the correct parameter value getting passed there. But Turing help me to debug that code!! I'll post with any progress.

Ryan

From: nuttx-***@public.gmane.org [mailto:nuttx-***@public.gmane.org] On Behalf Of Michael Smith
Sent: Wednesday, November 28, 2012 10:24 PM
To: nuttx-***@public.gmane.org
Subject: Re: [nuttx] Floating point in printf() functions



Ryan,

You might want to try a simple test to see whether there is an issue with varargs and floating point numbers.

Another option would be to try calling printf with a format string and matching arguments that contains at least 10 floating point numbers (because my cursory reading of AAPCS doesn't convince me that the compiler might not use all of d0-d7 for arguments - you might want to check the generated assembly).

If the last number is printed correctly, that would point the finger fairly squarely at a varargs / stdarg.h issue.

= Mike

On Nov 28, 2012, at 4:05 PM, "Sundberg, Ryan" <ryan.sundberg-DrNF7k4SyxHQT0dZR+***@public.gmane.org<mailto:ryan.sundberg-DrNF7k4SyxHQT0dZR+***@public.gmane.org>> wrote:




Hi Guys,

I'm noticing a bug with snprintf floating point strings for values > 1000, but only when compiled with -mfloat-abi=hard (on an stm32f4 arch)
The change log for 6.23 indicates some recent float fixes for printf functions.


nsh> float_test

str(%d): '40017' [ with value casted to int ]

str(%f): '0X017'

str(%.0f): '0X017'

str(%.4f): '0X017.0000'





When compiled with mfloat-abi=softfp, it works as expected. There are no compiler warnings that I'm ignoring.

Anyone have a clue?


Thanks,
Ryan Sundberg
Gregory N
2012-11-30 22:53:56 UTC
Permalink
Post by Sundberg, Ryan
That didn't work out - the issue is within dtoa(), my debugger shows the correct parameter value getting passed there. But Turing help me to debug that code!! I'll post with any progress.
No one wants to touch dtoa (me included) so it tends to stop everyone. You are talking with Mike Smith who, I think, understands these floating point issues better than anyone.

There are a couple of things that I don't understand. For one thing, Cortex-M4 hardware floating point is only for 32-bit 'float' types. Isn't that correct? printf and friends only deal only with type double. floats are expected to be converted to type double when they provided to printf.

You are looking at the value that is passed as input to dtoa and it is a correctly converted type double, correct? So the bottom line is that the inputs to dtoa are the same with and without hard floating pointing point, but the output from dtoa appears to differ with hard floating point enabled. Is that a correct assessment?

So to me, that would mean that something internal to the dtoa implementation is behaving differently with hardware floating point enabled. I wonder what would happen if you compiled that one file containing dtoa with software floating point.

Another thing that I don't understand is that other people are using hardware floating point. While I have heard a lot of complaints about dtoa, I haven't heard one before that is unique to hardware floating point being enabled.

Several bugs have been reported recently in the printf floating point conversion (by me and by Mike Smith). But I think that in all cases, the error was not really in dtoa() itself, but in the glue larger that converts the dtoa() return values to a printable string. Have you verified that dtoa() is actually returning bad values? Or is it returning good values that get mishandled after that?

Greg
Sundberg, Ryan
2012-12-01 00:03:11 UTC
Permalink
There are a couple of things that I don't understand. For one thing, Cortex-M4 hardware floating point is only for 32-bit 'float' types. Isn't that correct? printf and friends only deal only with type double. floats are expected to be converted to type double when they provided to printf.
Yes, that is correct. The FPU only supports single precision values.
You are looking at the value that is passed as input to dtoa and it is a correctly converted type double, correct? So the bottom line is that the inputs to dtoa are the same with and without hard floating pointing point, but the output from dtoa appears to differ with hard floating point enabled. Is that a correct assessment?
Also correct, the double parameter has the right value, but the string returned from dtoa is bad.
So to me, that would mean that something internal to the dtoa implementation is behaving differently with hardware floating point enabled. I wonder what would happen if you compiled that one file containing dtoa with software floating point.
I don't think I would be able to link it then?
Another thing that I don't understand is that other people are using hardware floating point. While I have heard a lot of complaints about dtoa, I haven't heard one before that is unique to hardware floating point being enabled.
When I get a chance, I'll try this on another test board with a similar arch and see if it has the same problem.
Several bugs have been reported recently in the printf floating point conversion (by me and by Mike Smith). But I think that in all cases, the error was not really in dtoa() itself, but in the glue larger that converts the dtoa() return values to a printable string. Have you verified that dtoa() is actually returning bad values? Or is it returning good values that get mishandled after that?
Dtoa() is returning the bad values.

One thing I tried was porting dtoa.c (attached) from the GCC trunk here http://gcc.gnu.org/viewcvs/trunk/libjava/classpath/native/fdlibm/dtoa.c?view=markup to see if that had the same behavior, which it did. Perhaps it's something to do with the Atollic pro 3.2.0 compiler I'm using.

When I have the time, I'll try to trace the execution through dtoa.c step by step with soft/hard float so the divergence can be pinpointed.

Ryan
Michael Smith
2012-12-01 03:49:53 UTC
Permalink
There are a couple of things that I don't understand. For one thing, Cortex-M4 hardware floating point is only for 32-bit 'float' types. Isn't that correct? printf and friends only deal only with type double. floats are expected to be converted to type double when they provided to printf.
You are looking at the value that is passed as input to dtoa and it is a correctly converted type double, correct? So the bottom line is that the inputs to dtoa are the same with and without hard floating pointing point, but the output from dtoa appears to differ with hard floating point enabled. Is that a correct assessment?
The M4 FPU only has instructions for operating on single-precision data, but the register file supports both float and double data, and by my quick re-reading AEABI says the caller-saved FP registers (d0-d7/s0-s15) are used for passing both single- and double-precision arguments.
So to me, that would mean that something internal to the dtoa implementation is behaving differently with hardware floating point enabled. I wonder what would happen if you compiled that one file containing dtoa with software floating point.
Very bad things, most likely, as that changes the way that floating-point arguments are expected to be passed. You would have to write an assembly-language shim that adjusted the arguments on the way in to dtoa().
Another thing that I don't understand is that other people are using hardware floating point. While I have heard a lot of complaints about dtoa, I haven't heard one before that is unique to hardware floating point being enabled.
We've had some fairly weird issues with floating-point printf that we have tended to avoid (emphasising telemetry over console logging in particular) rather than properly fix, however nothing that has looked as bad as this (mostly NAN/INF handling).

Every now and then when I have nothing better to do, I go looking for a compromise floating-point formatter that trades a little precision for the insanity of the Steele/Loitsch algorithms, but I haven't found a decent candidate that won't involve replacing printf() entirely, and add a dependency on the math library as well...

= Mike
Freddie Chopin
2012-12-01 08:41:05 UTC
Permalink
Post by Michael Smith
Very bad things, most likely, as that changes the way that
floating-point arguments are expected to be passed. You would have to
write an assembly-language shim that adjusted the arguments on the way
in to dtoa().
There's a third option - "softfp" which uses FPU but also uses "soft"
calling methods - it's the option designed to exactly the case here - to
link modules which use h/w FPU with modules which don't. You could
compile dtoa() with "soft" and link it to other parts of code that use
FPU that were built with "softfp".
Post by Michael Smith
Every now and then when I have nothing better to do, I go looking for a
compromise floating-point formatter that trades a little precision for
the insanity of the Steele/Loitsch algorithms, but I haven't found a
decent candidate that won't involve replacing printf() entirely, and add
a dependency on the math library as well...
I see that the function is taken from newlib, so I'd say that the code
is not wrong, something else is. You can easily check whether you see a
similar behavior with newlib but without NuttX's libc and you'll know
whether the problem is in dtoa() or not.

4\/3!!

Loading...