gul-cpp / gul14

General Utility Library for C++14
https://gul14.info/
GNU Lesser General Public License v2.1
2 stars 1 forks source link

to_number() test fails on Alpine Linux 3.19 #69

Closed alt-graph closed 7 months ago

alt-graph commented 8 months ago

By Soeren:

I tried to build the current release on Alpine 3.19 and got failures when testing:

1/1 all        FAIL            0.74s   exit status 4
>>> LD_LIBRARY_PATH=/tmp/build/libgul/src MALLOC_PERTURB_=64 ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 /tmp/build/libgul/tests/libgul-test
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ✀  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libgul-test is a Catch v2.13.7 host application.
Run with -? for options

-------------------------------------------------------------------------------
to_number(): min and subnormal floating point - long double
-------------------------------------------------------------------------------
../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:206
...............................................................................

../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:222: FAILED:
  REQUIRE( true == gul14::within_ulp(to_number<TestType>(ss.str()).value(), num, lenience) )
with expansion:
  true == false
with message:
  ss.str() := "3.36210314311209350626e-4932"

-------------------------------------------------------------------------------
to_number(): max and overflow floating point - long double
-------------------------------------------------------------------------------
../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:226
...............................................................................

../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:235: FAILED:
  REQUIRE( true == gul14::within_ulp(to_number<TestType>(numb).value(), max, lenience) )
with expansion:
  true == false

-------------------------------------------------------------------------------
to_number(): lowest and overflow floating point - long double
-------------------------------------------------------------------------------
../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:251
...............................................................................

../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:260: FAILED:
  REQUIRE( true == gul14::within_ulp(to_number<TestType>(numb).value(), lowest, lenience) )
with expansion:
  true == false

-------------------------------------------------------------------------------
to_number(): random round trip conversion - long double
-------------------------------------------------------------------------------
../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:311
...............................................................................

../../../home/grunewal/git/desy.de/doocs/library/common/libgul/tests/test_to_number.cc:348: FAILED:
  REQUIRE( true == gul14::within_ulp(*converted, num, 30) )
with expansion:
  true == false
with messages:
  i := 0
  numstr := "-2.08181233456417921937e-4933"
  conver := "-0"
  "subnormal " + std::to_string(++i_sub) := "subnormal 1"

===============================================================================
test cases:   351 |   347 passed | 4 failed
assertions: 25304 | 25300 passed | 4 failed

I was using GCC:

g++: (Alpine 13.2.1_git20231014) 13.2.1 20231014
meson: 1.3.0
Finii commented 7 months ago

Can reproduce:

$ sudo docker run --rm -it alpine
# apk add build-base openldap-dev libtirpc-dev zeromq-dev meson git
# mkdir home/fini
# cd home/fini
# git clone git clone https://github.com/gul-cpp/gul14.git
# cd gul14
# meson setup build
# ninja -C build test

...

../tests/test_to_number.cc:348: FAILED:
  REQUIRE( true == gul14::within_ulp(*converted, num, 30) )
with expansion:
  true == false
with messages:
  i := 1
  numstr := "-6.30992338596697469386e-4933"
  conver := "-0"
  "subnormal " + std::to_string(++i_sub) := "subnormal 2"

something is wrong with some long double tests

diff --git a/tests/test_to_number.cc b/tests/test_to_number.cc
index 3135a71..c9e1164 100644
--- a/tests/test_to_number.cc
+++ b/tests/test_to_number.cc
@@ -203,7 +203,7 @@ TEMPLATE_TEST_CASE("to_number(): integer lowest() values round-trip", "[to_numbe
     REQUIRE(to_number<TestType>(str).value() == std::numeric_limits<TestType>::lowest());
 }

-TEMPLATE_TEST_CASE("to_number(): min and subnormal floating point", "[to_number]", float, double, long double)
+TEMPLATE_TEST_CASE("to_number(): min and subnormal floating point", "[to_number]", float, double)
 {
     // Do no try subnormal if the type does not support it
     auto const max_divisor = std::numeric_limits<TestType>::has_denorm ? 4 : 1;
@@ -223,7 +223,7 @@ TEMPLATE_TEST_CASE("to_number(): min and subnormal floating point", "[to_number]
     }
 }

-TEMPLATE_TEST_CASE("to_number(): max and overflow floating point", "[to_number]", float, double, long double)
+TEMPLATE_TEST_CASE("to_number(): max and overflow floating point", "[to_number]", float, double)
 {
     auto const max = std::numeric_limits<TestType>::max();

@@ -248,7 +248,7 @@ TEMPLATE_TEST_CASE("to_number(): max and overflow floating point", "[to_number]"

 }

-TEMPLATE_TEST_CASE("to_number(): lowest and overflow floating point", "[to_number]", float, double, long double)
+TEMPLATE_TEST_CASE("to_number(): lowest and overflow floating point", "[to_number]", float, double)
 {
     auto const lowest = std::numeric_limits<TestType>::lowest();

@@ -309,7 +309,7 @@ auto random_float() -> Float
 }

 TEMPLATE_TEST_CASE("to_number(): random round trip conversion", "[to_number]",
-                   float, double, long double)
+                   float, double)
 {
Finii commented 7 months ago

As with some (?) Apple compilers the std::pow(long double, long double) is giving wrong answers with small values.

printf("-> %.40Le\n", std::pow(10.0L, -4932.0L));

/// alpine -> 1.0000000000000000028514628247895035728955e-4932
///                              2851e-4953              
///           1.0000000000000000000000000000000e-4932       
///                                64e-4953
/// ubuntu -> 0.9999999999999999999353031992835238908727e-4932

Alpine is roughly 50 times more off the exact value than Ubuntu, and that is several ULPs

alpine:  0 0001 : 1 000000000000001a (exp -16382) -> 0x1.0000000000000034p-16382
ubuntu:  0 0000 : 0 7fffffffffffffff (exp -16383) -> 0x7.fffffffffffffffp-16385

Whatever that output means, ubuntu is 1 ULP off the ideal, while Alpine is 0x1a == 26 ULPs off.

My debug output code that decodes the floating point number can be found below, keep in mind that this only works for the 80 bit floating point numbers (and not f0r 128 bit FP numbers, or smaller ones).

```c++ auto dumpld(long double ld) -> void { union float_inspection { long double fp; struct { uint64_t u; uint16_t m; } decode; }; float_inspection fi{ }; fi.fp = ld; printf(" %d %.4x : %.1d %.16lx (exp %d) -> %La\n", fi.decode.m >> 15, fi.decode.m & 0x3fff, !!(fi.decode.u >> 63), fi.decode.u & 0x7fffffffffffffff, (fi.decode.m & 0x3fff) - 0x3fff, ld); } ```

[1] https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format [2] https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format