Bug 224326

Summary: double subnormals are not well printed on printing with printf (and friends)
Product: Base System Reporter: Luis Colorado <luiscoloradourcola>
Component: miscAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Many People CC: marklmi26-fbsd, pstef
Priority: ---    
Version: 11.0-STABLE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
program run to get the expected and obtained output.
none
program to display correct values (except for rounding errors) none

Description Luis Colorado 2017-12-13 20:15:16 UTC
Created attachment 188809 [details]
program run to get the expected and obtained output.

subnormals are not recognized as such in doubles (they are in float) and long double.  I cannot do a make update to get the last version of the libc, as I'm in a Tier 2 (raspberry pi) architecture.  I'm running 11.0-STABLE.  I get this output for a program that consists in dividing by two a normalized number until I get zero:  (only the four first numbers are normalized)
(wrong output, expected follows)

0x0040000000000000 1.7800590868057611e-307 (ok, but normalized)
0x0030000000000000 8.9002954340288055e-308 (ok, but normalized)
0x0020000000000000 4.4501477170144028e-308 (ok, but normalized)
0x0010000000000000 2.2250738585072014e-308 (ok, but normalized)
0x0008000000000000 1.668805393880401e-308 (from here on, all are incorrect)
0x0004000000000000 1.3906711615670009e-308
0x0002000000000000 1.2516040454103008e-308
0x0001000000000000 1.1820704873319507e-308
0x0000800000000000 1.1473037082927757e-308
0x0000400000000000 1.1299203187731882e-308
0x0000200000000000 1.1212286240133944e-308
0x0000100000000000 1.1168827766334976e-308
0x0000080000000000 1.1147098529435491e-308
0x0000040000000000 1.1136233910985749e-308
0x0000020000000000 1.1130801601760878e-308
0x0000010000000000 1.1128085447148442e-308
0x0000008000000000 1.1126727369842225e-308
0x0000004000000000 1.1126048331189116e-308
0x0000002000000000 1.1125708811862561e-308
0x0000001000000000 1.1125539052199284e-308
0x0000000800000000 1.1125454172367646e-308
0x0000000400000000 1.1125411732451826e-308
0x0000000200000000 1.1125390512493917e-308
0x0000000100000000 1.1125379902514962e-308
0x0000000080000000 1.1125374597525484e-308
0x0000000040000000 1.1125371945030746e-308
0x0000000020000000 1.1125370618783376e-308
0x0000000010000000 1.1125369955659692e-308
0x0000000008000000 1.1125369624097849e-308
0x0000000004000000 1.1125369458316928e-308
0x0000000002000000 1.1125369375426468e-308
0x0000000001000000 1.1125369333981237e-308
0x0000000000800000 1.1125369313258622e-308
0x0000000000400000 1.1125369302897314e-308
0x0000000000200000 1.1125369297716661e-308
0x0000000000100000 1.1125369295126334e-308
0x0000000000080000 1.112536929383117e-308
0x0000000000040000 1.1125369293183589e-308
0x0000000000020000 1.1125369292859798e-308
0x0000000000010000 1.1125369292697902e-308
0x0000000000008000 1.1125369292616955e-308
0x0000000000004000 1.1125369292576481e-308
0x0000000000002000 1.1125369292556244e-308
0x0000000000001000 1.1125369292546125e-308
0x0000000000000800 1.1125369292541066e-308
0x0000000000000400 1.1125369292538537e-308
0x0000000000000200 1.1125369292537272e-308
0x0000000000000100 1.1125369292536639e-308
0x0000000000000080 1.1125369292536323e-308
0x0000000000000040 1.1125369292536165e-308
0x0000000000000020 1.1125369292536086e-308
0x0000000000000010 1.1125369292536046e-308
0x0000000000000008 1.1125369292536027e-308
0x0000000000000004 1.1125369292536017e-308
0x0000000000000002 1.1125369292536012e-308
0x0000000000000001 1.1125369292536009e-308

while expected behaviour is:

0x0040000000000000 1.7800590868057611e-307
0x0030000000000000 8.9002954340288055e-308
0x0020000000000000 4.4501477170144028e-308
0x0010000000000000 2.2250738585072014e-308
0x0008000000000000 1.1125369292536007e-308
0x0004000000000000 5.5626846462680035e-309
0x0002000000000000 2.7813423231340017e-309
0x0001000000000000 1.3906711615670009e-309
0x0000800000000000 6.9533558078350043e-310
0x0000400000000000 3.4766779039175022e-310
0x0000200000000000 1.7383389519587511e-310
0x0000100000000000 8.6916947597937554e-311
0x0000080000000000 4.3458473798968777e-311
0x0000040000000000 2.1729236899484389e-311
0x0000020000000000 1.0864618449742194e-311
0x0000010000000000 5.4323092248710971e-312
0x0000008000000000 2.7161546124355486e-312
0x0000004000000000 1.3580773062177743e-312
0x0000002000000000 6.7903865310888714e-313
0x0000001000000000 3.3951932655444357e-313
0x0000000800000000 1.6975966327722179e-313
0x0000000400000000 8.4879831638610893e-314
0x0000000200000000 4.2439915819305446e-314
0x0000000100000000 2.1219957909652723e-314
0x0000000080000000 1.0609978954826362e-314
0x0000000040000000 5.3049894774131808e-315
0x0000000020000000 2.6524947387065904e-315
0x0000000010000000 1.3262473693532952e-315
0x0000000008000000 6.631236846766476e-316
0x0000000004000000 3.315618423383238e-316
0x0000000002000000 1.657809211691619e-316
0x0000000001000000 8.289046058458095e-317
0x0000000000800000 4.1445230292290475e-317
0x0000000000400000 2.0722615146145237e-317
0x0000000000200000 1.0361307573072619e-317
0x0000000000100000 5.1806537865363094e-318
0x0000000000080000 2.5903268932681547e-318
0x0000000000040000 1.2951634466340773e-318
0x0000000000020000 6.4758172331703867e-319
0x0000000000010000 3.2379086165851934e-319
0x0000000000008000 1.6189543082925967e-319
0x0000000000004000 8.0947715414629834e-320
0x0000000000002000 4.0473857707314917e-320
0x0000000000001000 2.0236928853657458e-320
0x0000000000000800 1.0118464426828729e-320
0x0000000000000400 5.0592322134143646e-321
0x0000000000000200 2.5296161067071823e-321
0x0000000000000100 1.2648080533535912e-321
0x0000000000000080 6.3240402667679558e-322
0x0000000000000040 3.1620201333839779e-322
0x0000000000000020 1.5810100666919889e-322
0x0000000000000010 7.9050503334599447e-323
0x0000000000000008 3.9525251667299724e-323
0x0000000000000004 1.9762625833649862e-323
0x0000000000000002 9.8813129168249309e-324
0x0000000000000001 4.9406564584124654e-324
Comment 1 Luis Colorado 2017-12-14 20:49:56 UTC
Created attachment 188840 [details]
program to display correct values (except for rounding errors)

This is a simple program I wrote to get the expected values (compared also with glibc output, they differ in the two less significant digits at position 17)
Comment 2 Piotr Pawel Stefaniak freebsd_committer freebsd_triage 2021-10-05 20:04:47 UTC
I'm getting the expected output, but this is on amd64 and stable/13.
Comment 3 Piotr Pawel Stefaniak freebsd_committer freebsd_triage 2021-10-09 11:15:08 UTC
Actually, below is what I'm getting on stable/13.

amd64:
$ ./test | tail
0x0000000000000200 2.5296161067071825d-321
0x0000000000000100 1.2648080533535913d-321
0x0000000000000080 6.3240402667679563d-322
0x0000000000000040 3.1620201333839781d-322
0x0000000000000020 1.5810100666919891d-322
0x0000000000000010 7.9050503334599451d-323
0x0000000000000008 3.9525251667299726d-323
0x0000000000000004 1.9762625833649863d-323
0x0000000000000002 9.8813129168249318d-324
0x0000000000000001 4.9406564584124659d-324

arm64:
% ./test | tail
0x0000000000000200 2.5296161067071825d-321
0x0000000000000100 1.2648080533535913d-321
0x0000000000000080 6.3240402667679563d-322
0x0000000000000040 3.1620201333839781d-322
0x0000000000000020 1.5810100666919891d-322
0x0000000000000010 7.9050503334599451d-323
0x0000000000000008 3.9525251667299726d-323
0x0000000000000004 1.9762625833649863d-323
0x0000000000000002 9.8813129168249318d-324
0x0000000000000001 4.9406564584124659d-324

So better than 
0x0000000000000200 1.1125369292537272e-308
0x0000000000000100 1.1125369292536639e-308
0x0000000000000080 1.1125369292536323e-308
0x0000000000000040 1.1125369292536165e-308
0x0000000000000020 1.1125369292536086e-308
0x0000000000000010 1.1125369292536046e-308
0x0000000000000008 1.1125369292536027e-308
0x0000000000000004 1.1125369292536017e-308
0x0000000000000002 1.1125369292536012e-308
0x0000000000000001 1.1125369292536009e-308
but not exactly
0x0000000000000200 2.5296161067071823e-321
0x0000000000000100 1.2648080533535912e-321
0x0000000000000080 6.3240402667679558e-322
0x0000000000000040 3.1620201333839779e-322
0x0000000000000020 1.5810100666919889e-322
0x0000000000000010 7.9050503334599447e-323
0x0000000000000008 3.9525251667299724e-323
0x0000000000000004 1.9762625833649862e-323
0x0000000000000002 9.8813129168249309e-324
0x0000000000000001 4.9406564584124654e-324
Comment 4 Luis Colorado 2021-10-12 07:54:56 UTC
Hi Piotr,

Yeah, on intel it works.... I was working in a raspberry pi, model 2+, which is where I addressed the bug (more than four years ago!!!!)  The expected behaviour was produced by running the program in intel architecture.

I think the bug is related with the raspberry processor not supporting subnormals and the software accepting them as they are in intel, But I have no time to dig on this problem.  My apologies.
Comment 5 Piotr Pawel Stefaniak freebsd_committer freebsd_triage 2021-10-12 16:17:03 UTC
(In reply to Luis Colorado from comment #4)

Please note that "arm64" in comment #3 is non-intel (although not RPi as in your case but the first pinebook).
Comment 6 Luis Colorado 2021-10-13 09:00:44 UTC
arm64 is not the architecture I'm talking about, as the rpi 2+ is 32 bit arch and not arm64.  Anyway I suspect the problem will be also there, as both architectures will probably share the floating point unit.

But you tell me that you are getting correct results in AMD64 (which is the intel 64 bit architecture, and not ARM at all)  Sorry, but I don't get the point here.  It is four years this bug is rolling over there.  My impression is that arm architectures don't support 64bit floating point subnormals at all, and that's the reason the software is failing, as it doesn't cut the thing and makes them as 0 (which obviously the hardware is not doing)

IMHO, the floating point library should check if the processor supports subnormals or not, which is something required by the ieee standard, and round the values to 0.0, instead.  That is easy to check, as the exponent field is all zeros for subnormals.
Comment 7 Mark Millard 2021-10-13 19:09:26 UTC
(In reply to Luis Colorado from comment #4)

RPi2 v1.0 and v1.1 were Cortex-A7 (armv7) based.
RPi2 v1.2 was Cortext-A53 (aarch64) based.

(I sometimes have access to a v1.1 and/or v v1.2, but
not currently.)

RPi2 v1.2's can use either armv7 FreeBSD or aarch64 
FreeBSD.

So things can be confusing/ambiguus when RPi2 is used as
a point of reference. SO it is better to specify which
FreeBSD is in use, such as via:

# uname -apKU
FreeBSD OPiP2E_RPi2v11 14.0-CURRENT FreeBSD 14.0-CURRENT #10 main-n249978-032448cd2c52-dirty: Sat Oct  9 02:11:35 PDT 2021     root@CA72_16Gp_ZFS:/usr/obj/BUILDs/main-CA7-nodbg-clang/usr/main-src/arm.armv7/sys/GENERIC-NODBG-CA7  arm armv7 1400036 1400036

(Not an RPi* example.)
Comment 8 Mark Millard 2021-10-13 19:29:56 UTC
(In reply to Luis Colorado from comment #0)

On/for armv7, for compiling/linking the test program via
any of:

system clang (so: 12)
clang13 (from devel/llvm13)
gcc11 (from lang/gcc11)

and then running the test, all produce the e-308 "from here
on, all are incorrect" type of results.

Side note:

For reference,

# gcc11 -O2 -pedantic -Wall subnormal_test.c
subnormal_test.c: In function 'main':
subnormal_test.c:10:49: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   10 |                 printf("0x%016llx %-0.17lg\n", *(unsigned long long *)&val, val);
      |                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
subnormal_test.c:10:24: warning: '0' flag ignored with '-' flag in gnu_printf format [-Wformat=]
   10 |                 printf("0x%016llx %-0.17lg\n", *(unsigned long long *)&val, val);
      |                        ^~~~~~~~~~~~~~~~~~~~~~

and:

# clang13 -O2 -pedantic -Wall subnormal_test.c
subnormal_test.c:10:23: warning: flag '0' is ignored when flag '-' is present [-Wformat]
                printf("0x%016llx %-0.17lg\n", *(unsigned long long *)&val, val);
                                  ~~^~~~~~
Comment 9 Mark Millard 2021-10-13 20:05:48 UTC
(In reply to Mark Millard from comment #8)

For gcc11 I forgot : -Wl,-rpath=/usr/local/lib/gcc11
so that:

# ldd a.out
a.out:
        libgcc_s.so.1 => /usr/local/lib/gcc11/libgcc_s.so.1 (0x2008d000)
        libc.so.7 => /lib/libc.so.7 (0x200bc000)

(Not that it makes any difference in the bad -e308's that result.)