-
-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Wrong" output for double value #273
Comments
Heya @josesimoes - I'm not sure it's actually a bug, though I think it probably depends on what your expectation is :) 1234.567 can not be perfectly represented by a single- or double-precision float. See here: https://lukaskollmer.de/ieee-754-visualizer/ Or here, through https://www.h-schmidt.net/FloatConverter/IEEE754.html But, the double-precision representation does come very close, as you've seen. nanoprintf rounds to the final requested precision digit, so when you ask for nanoprintf will give you as much precision as you ask for, and then round to the final digit. That's what it's doing here, and I think it's giving you the expected result. You can see that gcc and clang also do not print Though, I'll cc @Okarss to spot-check me, if he's around and has a spare minute! :) (He just rewrote the entire floating-point conversion code recently.) |
@charlesnicholson wow! Thank you so much for the prompt and detailed reply. 👍🏻 😄 Yeap, I understand that this one can't be perfectly represented as float. That's why we're using it in one of the tests 😉 With the current embedded printf implementation that we're using (es-printf)[https://github.com/skirridsystems/es-printf] (for several years now) this is not happening. |
Gotcha :) Yeah, let's see if @Okarss chimes in on this one! |
Hello, guys! Basically you both have understood what's happening correctly and indeed it is not a bug, but a deliberate compromise by design. To get the smallest code size, the float implementation in nanoprintf sacrifices the absolute mathematical correctness and therefore will not print exactly the same values as the full implementations. As the README file explains, with a conversion integer type width of N bits on average the algorithm retains Currently you are using (most likely the default) 32-bit processing. One thing you can do is try the 64-bit processing by defining this for nanoprintf: #define NANOPRINTF_CONVERSION_FLOAT_TYPE uint64_t For this particular test case the number then will be printed perfectly, but take a note that it just makes the processing more accurate, not perfect. Also take a note that it will pull in the runtime code for 64-bit integer arithmetic if your other code is not using it already. Apart from the README file, one can find additional fine details about the implementation and floating point math in general in #221 and #263. |
OK, I think that will get us there. And yes, this is running on 32bits systems (although we have a virtual device running on 64-bits). Out of curiosity, a build from one of our targets, has 322756B with default and goes to 323044B after adding the define for uint64_t. Again, pretty acceptable considering that we need it for this to work. Thank you, guys, for the awesome support and congrats on this fine library! 👍🏻 😄 |
@josesimoes that's great to hear! I'm curious- do you happen to have any size or performance benchmarks that you could share as a part of your work? I'm always eager to hear how nanoprintf performs "in the wild" :) Also, thanks to @Okarss for supporting :) |
I'm affraid I have a couple more... Ouput of and when testing the max values:
I get: |
For the The The additional zeroes printed before the npf_snprintf(..., ..., "%.5g", 1e18); It outputs |
OK... As it is now, I have the double as uint64_t as you've suggested and also the buffer set to 48. Tried to increase it to 64, but it didn't improved. This is running on several architures, Cortex-M for STM32, all ESP32 series, Silabs GG11, NXP and a virtual device build with the latest MVC++. Appreciate your advice or any fix that's required. Otherwise this is a blocker for us... |
The For 64-bit |
@josesimoes - One of the core value propositions of nanoprintf is that it's small above all else. @Okarss's recent overhaul of the floating point formatting code was very exciting because it dramatically increased the precision + correctness of formatting and made the code smaller! But, npf is by design not meant to have features that are at times desirable but complex and large: e.g. bit-perfect round trips between float and string, perfect rounding and precision, etc. There are many cases where developers might not care about these floating-point processing goals, are happy with a "good enough" implementation, and just want a full-featured printf that works in tiny places. This is nanoprintf's "sweet spot". It would be a bummer if npf didn't work for you, but if you need perfect-precision double-formatting then it's possible that it's not the right fit for your needs :( |
Sure! I get that. I was looking for alternative implementations and nanoprintf looked great. Not oy because of the name nano. 😅 Let's see if we can figure it out, if not, that's OK and I'll still keep it on my bookmarks. 😉 |
@charlesnicholson as I've reported above, I've copied the changes in the draft PR #274. Wanted to confirm if these two configurations are really incompatible. |
The The Again, this is all explained in the "Floating-Point" chapter in the README file. It's just a few sentences there, but they explain the expected accuracy and the range of values, which will be printed mathematically perfect. So in short:
|
Hey,
I was testing this library to replace the current implementation of printf for .NET nanoFramework.
Everything looks great and all tests pass, except a couple of ones trying to print a double
1234.567
which, using the format specifier%0.19G
is being printed as1234.5669999998062849045
I've played around a bit and found that if I use up to
%0.9G
it outputs nicelly1234.567000000
. Above nine it messes up with the rounding.Is this something that can be easily fixed?
Thanks!
The text was updated successfully, but these errors were encountered: