Questions about powf inaccuracies on ARM Cortex-M7

Matthias Weber <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Hi all,

first of all thanks for maintaining newlib and for providing help on the 
mailing list. Keep up your nice work!

I usually do not look behind the scenes of a standard library, but 
reading about "fixes to powf" in "Major changes in newlib version 4.5.0" 
in the NEWS file caught my attention.

I've tried to understand what this means and whether it affects 
calculations on ARM Cortex-M7. I am asking for some guidance here - 
maybe you can enlighten me.

Background/context:
In thread https://sourceware.org/pipermail/newlib/2024/021294.html, 
Fabian submitted powf inaccuracy patches (taken from FreeBSD and 
authored by Bruce Evans).
I am using Arm GNU Toolchain 11.3.rel1 (released on 08.08.2022) for an 
ARM Cortex-M7 based uC which seems to ship a prebuilt 
newlib/newlib-nano. I am linking with newlib-nano.
The toolchain's release notes s tates commit 
bfee9c6ab0c3c9a5742e84509d01ec6472aa62c4 of the newlib-cygwin git repo.
I've tracked this down and it seems that this is no specific release 
version from December but rather an intermediate snapshot between 
versions 4.3.0 (2023-01-20) and 4.2.0 (2021-12-31). So this version is 
"quite old" and does not cover the above mentioned major change of 
newlib version 4.5.0.
I am trying to find out whether upgrading to newlib-nano 4.5.0 may 
improve accuracy or if I am not affected at all (as the messages 
explicitely mention i386).

For a quick test, I've compiled and ran the following code on my target 
to see if I could reproduce the issue:

```
     // Test powf functionality for inaccuracies
     float x = -1.1;
     float y = 101.0;
     float z;
     z = powf(x, y);

     float a = 0.9999999;
     float b = -2.9999995;
     float c;
     c = powf(a, b);
```

I then took a look at the actual values using GDB:

```
(gdb) p/x x
$30 = 0xbf8ccccd
(gdb) p/x y
$31 = 0x42ca0000
(gdb) p/x z
$32 = 0xc66cdad4
(gdb) p z
$86 = -15158.707

(gdb) p/x a
$33 = 0x3f7ffffe
(gdb) p/x b
$34 = 0xc03ffffe
(gdb) p c
$87 = 1.00000036
(gdb) p/x c
$35 = 0x3f800003
```

So the first calculation seems to yield the correct result (variable z) 
whereas the second one seems to be wrong (variable c) - when comparing 
to the results shared in the mailing list:
The wrong result there was 1.0000002 (hex 3F800002) whereas it was 
described to should have yielded 1.0000001 (hex 3F800001).
As you can see, I even got 1.00000036 (hex 0x3f800003) -- which is even 
further off.

Having taken a second closer look, revealed that the input variable a is 
also slightly off: 0x3f7ffffe (in the mailing list: hex 3F7FFFFF).

```
(gdb) p a
$124 = 0.999999881
```
Why does my compiler(?) treat the literal floating-point literal 
differently?

Unfortunately, I was unable to step into powf as GDB claims:
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libm/common/sf_pow.c: 
No such file or directory.

I was unable to replace/fix the search path/ redirect it to the local 
checkout of the newlib-cygwin repo. This is beyond my GDB skills for 
now. Maybe you can give me a hint here.

As the submitted patch affects newlib/libm/math/ef_pow.c, I was 
wondering if I was affected at all because you can see that GDB tried to 
search in a different file: newlib/libm/common/sf_pow.c

Are ef_pow.c and sf_pow.c related or are they completely different 
implementations and so the patch does not help me anyways?
"sf" seems to stand for "Single-precision", what does the "ef" in 
ef_pow.c stand for?
What am I missing?

Many thanks,
Matthias
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.