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.)