-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
py/formatfloat: Fix exact int formatting on 32-bit mingw. #10267
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
Conversation
This fixes the test failures seen in https://github.com/micropython/micropython/actions/runs/3726500144/jobs/6319986435 |
I don't know x86 assembly but here is the difference this change makes. Before (using `pow()`):
After (using `powl()`):
They look quite similar - neither calls any actual functions, so gcc must be optimising the |
Code size report:
|
5232f70
to
fcb3d6d
Compare
Code size report:
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #10267 +/- ##
==========================================
+ Coverage 98.36% 98.49% +0.13%
==========================================
Files 159 155 -4
Lines 21093 20528 -565
==========================================
- Hits 20748 20220 -528
+ Misses 345 308 -37 ☔ View full report in Codecov by Sentry. |
I'm not sure this is the right solution. What's probably happening is that it's using 80-bit float precision internally and that's making a slight difference to rounding in the uPy float algorithm. Or the compiler (with optimisation) ignores the IEEE standard; see Maybe there's a compiler option that can be used to fix this? Maybe we can compile floatformat.c with -O0 unconditionally on mingw32? Otherwise we can simply skip this test on mingw32 (see RUN_TESTS_SKIP in ports/windows/Makefile). |
We can actually just not optimize the one function. And I have confirmed it fixes the problem too. But since the problem is just with the pow() functions, it seemed like a bit overkill for such a large function compared to using powl() which just changes a few CPU instructions. diff --git a/py/formatfloat.c b/py/formatfloat.c
index fc1b2fe7f..1daee1360 100644
--- a/py/formatfloat.c
+++ b/py/formatfloat.c
@@ -98,6 +98,11 @@ static inline int fp_expval(FPTYPE x) {
return (int)((fb.i >> MP_FLOAT_FRAC_BITS) & (~(0xFFFFFFFF << MP_FLOAT_EXP_BITS))) - MP_FLOAT_EXP_OFFSET;
}
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE && defined(__GNUC__) && defined(__MINGW32__) && defined(__i386__)
+// When optimizations are enabled using mingw's gcc, it breaks pow(double, double)
+// and gives wrong results.
+__attribute__((optimize("O0")))
+#endif
int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
char *s = buf; |
I suppose another option could be to create a wrapper around |
I think I found the answer: https://lemire.me/blog/2020/06/26/gcc-not-nearest/ |
fcb3d6d
to
847bc69
Compare
38e455a
to
7d96388
Compare
@@ -84,6 +84,11 @@ ifneq ($(FROZEN_MANIFEST),) | |||
CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -DMICROPY_MODULE_FROZEN_MPY=1 -DMPZ_DIG_SIZE=16 | |||
endif | |||
|
|||
ifeq ($(shell $(CC) -dumpmachine),i686-w64-mingw32) | |||
# https://lemire.me/blog/2020/06/26/gcc-not-nearest | |||
CFLAGS += -msse -mfpmath=sse -march=pentium4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a more substantial comment, eg "force gcc to use IEEE correct rounding when optimising float constants at compile time"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
611b631
to
e58d368
Compare
FYI for the msvc build we also use |
When compiler optimizations are enabled on the mingw version of gcc, we are getting failing tests because of rounding issues, for example: print(float("1e24")) would print 9.999999999999999e+23 instead of 1e+24 It turns out special compiler options are needed to get GCC to use the SSE instruction set instead of the 387 coprocessor (which uses 80-bit precision internall). Signed-off-by: David Lechner <david@pybricks.com>
e58d368
to
23342ef
Compare
Upgrade ESP-IDF v5.3.2 to v5.4.1
When compiler optimizations are enabled on the mingw version of gcc targeting 32-bit Windows, we are getting failing tests because of rounding issues, for example:
would print
instead of
We can work around the issue by using
powl()
instead ofpow()
inmp_format_float()
on affected targets.