https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121403

            Bug ID: 121403
           Summary: to_chars -> from_chars round trip fails for long
                    double on powerpc64le
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: cassio.neri at gmail dot com
  Target Milestone: ---

[charconv.to.chars]/2 says that a round trip to_chars -> from_chars should
recover the original floating-point value:

"The functions that take a floating-point value but not a precision parameter
ensure that the string representation consists of the smallest number of
characters such that there is at least one digit before the radix point (if
present) and parsing the representation using the corresponding from_chars
function recovers value exactly."

I added this test to trunk (be377ef9ce3eb870ffd18ac02dabe32260dfcb6f):

// { dg-do run { target c++14 } }
// { dg-require-string-conversions "" }

#include <charconv>
#include <iostream>
#include <testsuite_hooks.h>

int main() {

        long double const x = 1.0l + 1.0e-17l;

        char str[30] = {};
        auto const [ptr1, ec1] = std::to_chars(str, str + sizeof(str) - 1, x);
        VERIFY(ec1 == std::errc{});

        auto const size = ptr1 - str;

        long double y;
        auto const [ptr2, ec2] = std::from_chars(str, str + size, y);
        VERIFY(ec2 == std::errc{});

        std::cerr << "diff = " << x - y << '\n';
        VERIFY(x == y);
}

It fails on powerpc64le, yielding:

diff = 1.07852e-32
[...]/src/libstdc++-v3/testsuite/20_util/to_chars/5.cc:23: int main():
Assertion 'x == y' failed.
FAIL: 20_util/to_chars/5.cc  -std=gnu++17 execution test

I'm working on to_chars, replacing Ryu with Tejú Jaguá, but I don't think the
problem is there. (For the avoidance of doubt, the test above was run using Ryu
but I don't have much hope that Tejú Jaguá will help.) I don't believe the
problem is in from_chars either. This is another issue on platforms where long
double is the IBM128 format, aka double-double. (See also bug 61399.)

Furthermore, the implementation of IBM128 allows the upper and lower parts to
have very different exponents. This causes issues for the shortest
representation. For instance, we can set x1 = 1.0l + __LDBL_DENORM_MIN__ (upper
= 1 and lower = 2^-1074) and x2 = 1.0l + 2.0l *  __LDBL_DENORM_MIN__ (upper = 1
and lower = 2*2^-1074) and the shortest representation that allows
distinguishing x1 and x2 should have about 325 digits as the bc script below
suggests:

scale=1074
1 + 1 * 2^(-1074)
1.[323 zeros]4...
1 + 2 * 2^(-1074)
1.[323 zeros]9...

Neither Ryu or Tejú Jaguá can produce those many digits. For them to work,
there should be some restriction on the exponents. Something like 0 <=
upper_exponent - lower_exponent < 53. (More research is needed to find the
exact condition.)

Reply via email to