float() different result returned for ppc64 vs x86_64

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

float() different result returned for ppc64 vs x86_64

Post by mksully22 » Tue Oct 02, 2018 6:13 pm

My understanding is that all hardware/software should implement https://en.wikipedia.org/wiki/IEEE_754 and return the same results. However when issuing float operations I see differences in results that cause the float_parse.py test to fail between ppc64 and x86_64:

PPC64 result:
~/aports/testing/micropython/src/micropython-1.9.4/tests $ ../ports/unix/micropython
MicroPython v3.8.0-1909-g685fa426c5-dirty on 2018-09-11; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> float('.' + '9' * 70)
1.000000000000001

X86_64
Linux 1060f6cfbd6b
~/aports/testing/micropython/src/micropython-1.9.4/tests $ ../ports/unix/micropython
MicroPython v3.8.0-1909-g685fa426c5-dirty on 2018-09-11; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> float('.' + '9' * 70)
1.0

jickster
Posts: 511
Joined: Thu Sep 07, 2017 8:57 pm

Re: float() different result returned for ppc64 vs x86_64

Post by jickster » Tue Oct 02, 2018 6:25 pm

I KNOW this issue has been posted AND addressed on the forum somewhere.

mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

Re: float() different result returned for ppc64 vs x86_64

Post by mksully22 » Tue Oct 02, 2018 6:45 pm

There were a couple of issues posted in thread viewtopic.php?f=3&t=5247 but the inconsistency between the ppc64 and x86_64 result wasn't addressed so was split out here. Do you know of another thread? I searched but couldn't find a specific resolution? Thanks

jickster
Posts: 511
Joined: Thu Sep 07, 2017 8:57 pm

Re: float() different result returned for ppc64 vs x86_64

Post by jickster » Tue Oct 02, 2018 6:48 pm

That’s the one I was thinking of. I see your point why it’s not the same kind of difference.


There may be two separate issues here:
the binary value that float() outputs AND
the value print() outputs.

Put a breakpoint in C code of both cases and compare the binary value of the float object that’s in memory and reply back.


Sent from my iPhone using Tapatalk Pro

mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

Re: float() different result returned for ppc64 vs x86_64

Post by mksully22 » Tue Oct 02, 2018 9:08 pm

I ran across https://bugs.mysql.com/bug.php?id=82760 that describes how floating point calculations can be a bit different on some cpu types when using the "-Os" compiler optimization settings. Because -Os enables the -fexpensive-optimizations option which causes ppc64 to compute floating point operations slightly differently. It is suggested from the above link that one of these enabled "expensive-optimizations" is to make use of the Fuse Multiply-Add instructions on ppc64 that are responsible for the slight differences in calculation. One suggested way to correct this is to use the -ffp-contract=off to disable the use of the Fused Multiply-Aadd instructions. I tried the following patch successfully to fix the issue on ppc64:

--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -30,7 +30,7 @@
CFLAGS += -g
COPT = -O0
else
-COPT = -Os -fdata-sections -ffunction-sections -DNDEBUG
+COPT = -Os -ffp-contract=off -fdata-sections -ffunction-sections -DNDEBUG
# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra
# security for detecting buffer overflows. Some distros (Ubuntu at the very least)
# have it enabled by default.

mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

Re: float() different result returned for ppc64 vs x86_64

Post by mksully22 » Wed Oct 03, 2018 1:48 pm

As suggested, to see the values returned from a "float('.' + '9' * 70)" operation a breakpoint was added at float_print().
When hit the value of self->value ( and o_val) shows that when building micropython with default cflags x86_64 computes a float value of 1, while ppc64 computes a float value of 1.0000000000000009

x86_64:
>>> float('.' + '9' * 70)
Breakpoint 1, float_print (print=0x5555555c2860 <mp_sys_stdout_print>, o_in=0x7ffff7d62e40, kind=PRINT_REPR) at ../../py/objfloat.c:109
109 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(gdb) step
111 mp_float_t o_val = mp_obj_float_get(o_in);
(gdb) step
mp_obj_float_get (self_in=0x7ffff7d62e40) at ../../py/obj.h:106
106 { return ((((mp_int_t)(o)) & 3) == 0); }
(gdb) step
208 return self->value;
(gdb) print self->value
$1 = 1
(gdb) step
float_print (print=0x5555555c2860 <mp_sys_stdout_print>, o_in=<optimized out>, kind=<optimized out>) at ../../py/objfloat.c:123
123 mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
(gdb) print o_val
$2 = 1
(gdb) cont
Continuing.
1.0
>>> quit

ppc64 without -ffp-contract=off
>>> float('.' + '9' * 70)
Breakpoint 1, 0x00000001000313ac in float_print (print=0x10008d940 <mp_sys_stdout_print>, o_in=0x7ffff7cd7360, kind=PRINT_REPR) at ../../py/objfloat.c:109
109 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(gdb) list
104
105 return val;
106 }
107 #endif
108
109 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
110 (void)kind;
111 mp_float_t o_val = mp_obj_float_get(o_in);
112 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
113 char buf[16];
(gdb) next
111 mp_float_t o_val = mp_obj_float_get(o_in);
(gdb) step
mp_obj_float_get (self_in=0x7ffff7cd7360) at ../../py/obj.h:106
106 { return ((((mp_int_t)(o)) & 3) == 0); }
(gdb) step
208 return self->value;
(gdb) step
float_print (print=0x10008d940 <mp_sys_stdout_print>, o_in=<optimized out>, kind=<optimized out>) at ../../py/objfloat.c:123
123 mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
(gdb) print o_val
$10 = 1.0000000000000009
(gdb) cont
Continuing.
1.000000000000001
>>>
[Inferior 1 (process 144200) exited normally]
(gdb)


When adding the -ffp-contract=off to cflags and rebuilding micropython ppc64 now returns a self->value (1) for the float operation consistent with x86_64.

ppc64 with -ffp-contract=off
>>> float('.' + '9' * 70)
Breakpoint 1, 0x00000001000313d0 in float_print (print=0x10008d940 <mp_sys_stdout_print>, o_in=0x7ffff7cd6e20, kind=PRINT_REPR) at ../../py/objfloat.c:109
109 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(gdb) list
104
105 return val;
106 }
107 #endif
108
109 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
110 (void)kind;
111 mp_float_t o_val = mp_obj_float_get(o_in);
112 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
113 char buf[16];
(gdb) step
111 mp_float_t o_val = mp_obj_float_get(o_in);
(gdb) step
mp_obj_float_get (self_in=0x7ffff7cd6e20) at ../../py/obj.h:106
106 { return ((((mp_int_t)(o)) & 3) == 0); }
(gdb) step
208 return self->value;
(gdb) step
float_print (print=0x10008d940 <mp_sys_stdout_print>, o_in=<optimized out>, kind=<optimized out>) at ../../py/objfloat.c:123
123 mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
(gdb) print o_val
$1 = 1
(gdb) continue
Continuing.
1.0

Note: As a check, rebuilding the x86_64 micropython binary with the fp-contract=off does not change the value returned for the float operation.

jickster
Posts: 511
Joined: Thu Sep 07, 2017 8:57 pm

Re: float() different result returned for ppc64 vs x86_64

Post by jickster » Wed Oct 03, 2018 3:22 pm

So problem solved?

mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

Re: float() different result returned for ppc64 vs x86_64

Post by mksully22 » Wed Oct 03, 2018 3:43 pm

If consistency across architectures to meet https://en.wikipedia.org/wiki/IEEE_754 is the objective then it would seem to be necessary to build with the -ffp-contract=off. I think this change would fix the problem as long as there are no objections?

jickster
Posts: 511
Joined: Thu Sep 07, 2017 8:57 pm

Re: float() different result returned for ppc64 vs x86_64

Post by jickster » Wed Oct 03, 2018 3:46 pm

mksully22 wrote:If consistency across architectures to meet https://en.wikipedia.org/wiki/IEEE_754 is the objective then it would seem to be necessary to build with the -ffp-contract=off. I think this change would fix the problem as long as there are no objections?
You should create an issue on github and link to this post to demonstrate the discrepancy.

Also create the pull request yourself since this involves only a compile options change and should be simple and quick for admins to accept or reject.


Sent from my iPhone using Tapatalk Pro

mksully22
Posts: 9
Joined: Tue Sep 11, 2018 12:07 pm

Re: float() different result returned for ppc64 vs x86_64

Post by mksully22 » Wed Oct 03, 2018 4:04 pm

I will do that. Thanks!

Post Reply