From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id D5389385740D for ; Wed, 19 Oct 2022 12:59:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D5389385740D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666184355; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=azjICH4r99xrm0sCGYq2lohewEgueH+XgzD/PhCjBvw=; b=A4SYOA8eSpyDFlX2L62Pn1cvlxyfjy0krNWG3kIh/4gQW3HgxxepFBEWubKBx4CNbTUDh0 i5h+Qmy10uW/eqDiXxd6q8jcrFBT5QdSZ/JSnrnXDDD5bcx2Azo8rdFqzAg+l4XJOKXogI nBO/Lp/WazyaWFG0RdHSniwbMe9aTQQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-649-bb9D6osuNHWviVLo7mg81Q-1; Wed, 19 Oct 2022 08:59:14 -0400 X-MC-Unique: bb9D6osuNHWviVLo7mg81Q-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D586C80650C; Wed, 19 Oct 2022 12:59:13 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.252]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 3A7BF404CD80; Wed, 19 Oct 2022 12:59:13 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 29JCx9nm3957614 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 19 Oct 2022 14:59:10 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 29JCx4aL3957613; Wed, 19 Oct 2022 14:59:04 +0200 Date: Wed, 19 Oct 2022 14:59:04 +0200 From: Jakub Jelinek To: Jonathan Wakely , Patrick Palka Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Subject: [PATCH] libstdc++-v3: Some std::*float*_t charconv and i/ostream overloads Message-ID: Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hi! The following patch adds the easy part of , and changes for extended floats. In particular, for the first one only overloads where the _Float* has the same format as float/double/long double and for the latter two everything but the _GLIBCXX_HAVE_FLOAT128_MATH case. For charconv, I'm not really familiar with it, I'm pretty sure we need new libstdc++.so.6 side implementation of from_chars for {,b}float16_t and for to_chars not really sure but for unspecified precision if it should emit minimum characters that to_chars then can unambiguously parse, I think it is less than in the float case. For float128_t {to,from}_chars I think we even have it on the library side already, just ifdefed for powerpc64le only. For i/o stream operator<>, not sure what is better, if not providing anything at all, or doing what we in the end do if user doesn't override the virtual functions, or use {to,from}_chars under the hood, something else? Besides this, the patch adds some further missed // { dg-options "-std=gnu++2b" } spots, I've also noticed I got the formatting wrong in some testcases by not using spaces around VERIFY conditions and elsewhere by having space before ( for calls. The testsuite coverage is limited, I've added test for from_chars because it was easy to port, but not really sure what to do about to_chars, it has for float/double huge testcases which would be excessive to repeat. And for i/ostream not really sure what exactly is worth testing. Tested on x86_64-linux with --target_board=unix/-std=gnu++23, ok for trunk? 2022-10-19 Jakub Jelinek * include/std/charconv (from_chars, to_chars): Add _Float{32,64,128} overloads for cases where those types match {float,double,long double}. * include/std/istream (basic_istream::operator>>): Add _Float{16,32,64,128} and __gnu_cxx::__bfloat16_t overloads. * include/std/ostream (basic_ostream::operator<<): Add _Float{16,32,64,128} and __gnu_cxx::__bfloat16_t overloads. * testsuite/20_util/from_chars/8.cc: New test. * testsuite/26_numerics/headers/cmath/nextafter_c++23.cc (test): Formatting fixes. * testsuite/26_numerics/headers/cmath/functions_std_c++23.cc: Add dg-options "-std=gnu++2b". (test_functions, main): Formatting fixes. * testsuite/26_numerics/headers/cmath/c99_classification_macros_c++23.cc: Add dg-options "-std=gnu++2b". --- libstdc++-v3/include/std/charconv.jj 2022-10-17 12:29:33.805012519 +0200 +++ libstdc++-v3/include/std/charconv 2022-10-19 11:54:03.049992722 +0200 @@ -675,6 +675,45 @@ namespace __detail from_chars_result from_chars(const char* __first, const char* __last, long double& __value, chars_format __fmt = chars_format::general) noexcept; + +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + inline from_chars_result + from_chars(const char* __first, const char* __last, _Float32& __value, + chars_format __fmt = chars_format::general) noexcept + { + float __val; + from_chars_result __res = from_chars(__first, __last, __val, __fmt); + if (__res.ec == errc{}) + __value = __val; + return __res; + } +#endif + +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + inline from_chars_result + from_chars(const char* __first, const char* __last, _Float64& __value, + chars_format __fmt = chars_format::general) noexcept + { + double __val; + from_chars_result __res = from_chars(__first, __last, __val, __fmt); + if (__res.ec == errc{}) + __value = __val; + return __res; + } +#endif + +#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + inline from_chars_result + from_chars(const char* __first, const char* __last, _Float128& __value, + chars_format __fmt = chars_format::general) noexcept + { + long double __val; + from_chars_result __res = from_chars(__first, __last, __val, __fmt); + if (__res.ec == errc{}) + __value = __val; + return __res; + } +#endif #endif #if defined __cpp_lib_to_chars @@ -701,6 +740,53 @@ namespace __detail chars_format __fmt) noexcept; to_chars_result to_chars(char* __first, char* __last, long double __value, chars_format __fmt, int __precision) noexcept; + +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + inline to_chars_result + to_chars(char* __first, char* __last, _Float32 __value) noexcept + { return to_chars(__first, __last, float(__value)); } + inline to_chars_result + to_chars(char* __first, char* __last, _Float32 __value, + chars_format __fmt) noexcept + { return to_chars(__first, __last, float(__value), __fmt); } + inline to_chars_result + to_chars(char* __first, char* __last, _Float32 __value, + chars_format __fmt, int __precision) noexcept + { return to_chars(__first, __last, float(__value), __fmt, __precision); } +#endif + +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + inline to_chars_result + to_chars(char* __first, char* __last, _Float64 __value) noexcept + { return to_chars(__first, __last, double(__value)); } + inline to_chars_result + to_chars(char* __first, char* __last, _Float64 __value, + chars_format __fmt) noexcept + { return to_chars(__first, __last, double(__value), __fmt); } + inline to_chars_result + to_chars(char* __first, char* __last, _Float64 __value, + chars_format __fmt, int __precision) noexcept + { return to_chars(__first, __last, double(__value), __fmt, __precision); } +#endif + +#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + inline to_chars_result + to_chars(char* __first, char* __last, _Float128 __value) noexcept + { return to_chars(__first, __last, static_cast(__value)); } + inline to_chars_result + to_chars(char* __first, char* __last, _Float128 __value, + chars_format __fmt) noexcept + { + return to_chars(__first, __last, static_cast(__value), __fmt); + } + inline to_chars_result + to_chars(char* __first, char* __last, _Float128 __value, + chars_format __fmt, int __precision) noexcept + { + return to_chars(__first, __last, static_cast(__value), __fmt, + __precision); + } +#endif #endif _GLIBCXX_END_NAMESPACE_VERSION --- libstdc++-v3/include/std/istream.jj 2022-10-03 18:00:58.977655275 +0200 +++ libstdc++-v3/include/std/istream 2022-10-19 13:16:33.633828491 +0200 @@ -225,6 +225,94 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_extract(__f); } ///@} +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + __attribute__((__always_inline__)) + __istream_type& + operator>>(_Float16& __f) + { + float __flt; + __istream_type& __ret = _M_extract(__flt); + ios_base::iostate __err = ios_base::goodbit; + if (__flt < -__FLT16_MAX__) + { + __f = -__FLT16_MAX__; + __err = ios_base::failbit; + } + else if (__flt > __FLT16_MAX__) + { + __f = __FLT16_MAX__; + __err = ios_base::failbit; + } + else + __f = static_cast<_Float16>(__flt); + if (__err) + this->setstate(__err); + return __ret; + } +#endif + +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + __attribute__((__always_inline__)) + __istream_type& + operator>>(_Float32& __f) + { + float __flt; + __istream_type& __ret = _M_extract(__flt); + __f = static_cast<_Float32> (__flt); + return __ret; + } +#endif + +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + __attribute__((__always_inline__)) + __istream_type& + operator>>(_Float64& __f) + { + double __dbl; + __istream_type& __ret = _M_extract(__dbl); + __f = static_cast<_Float64> (__dbl); + return __ret; + } +#endif + +#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + __attribute__((__always_inline__)) + __istream_type& + operator>>(_Float128& __f) + { + long double __ldbl; + __istream_type& __ret = _M_extract(__ldbl); + __f = static_cast<_Float128> (__ldbl); + return __ret; + } +#endif + +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + __attribute__((__always_inline__)) + __istream_type& + operator>>(__gnu_cxx::__bfloat16_t & __f) + { + float __flt; + __istream_type& __ret = _M_extract(__flt); + ios_base::iostate __err = ios_base::goodbit; + if (__flt < -__BFLT16_MAX__) + { + __f = -__BFLT16_MAX__; + __err = ios_base::failbit; + } + else if (__flt > __BFLT16_MAX__) + { + __f = __BFLT16_MAX__; + __err = ios_base::failbit; + } + else + __f = static_cast<__gnu_cxx::__bfloat16_t>(__flt); + if (__err) + this->setstate(__err); + return __ret; + } +#endif + /** * @brief Basic arithmetic extractors * @param __p A variable of pointer type. --- libstdc++-v3/include/std/ostream.jj 2022-10-03 18:00:58.996655019 +0200 +++ libstdc++-v3/include/std/ostream 2022-10-19 12:50:49.861798581 +0200 @@ -235,6 +235,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_insert(__f); } ///@} +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + __attribute__((__always_inline__)) + __ostream_type& + operator<<(_Float16 __f) + { + return _M_insert(static_cast(__f)); + } +#endif + +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + __attribute__((__always_inline__)) + __ostream_type& + operator<<(_Float32 __f) + { + return _M_insert(static_cast(__f)); + } +#endif + +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + __attribute__((__always_inline__)) + __ostream_type& + operator<<(_Float64 __f) + { + return _M_insert(static_cast(__f)); + } +#endif + +#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + __attribute__((__always_inline__)) + __ostream_type& + operator<<(_Float128 __f) + { + return _M_insert(static_cast(__f)); + } +#endif + +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + __attribute__((__always_inline__)) + __ostream_type& + operator<<(__gnu_cxx::__bfloat16_t __f) + { + return _M_insert(static_cast(__f)); + } +#endif + /** * @brief Pointer arithmetic inserters * @param __p A variable of pointer type. --- libstdc++-v3/testsuite/20_util/from_chars/8.cc.jj 2022-10-19 12:02:43.164952247 +0200 +++ libstdc++-v3/testsuite/20_util/from_chars/8.cc 2022-10-19 12:20:55.466149324 +0200 @@ -0,0 +1,367 @@ +// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2b" } +// { dg-do run { target c++23 } } +// { dg-add-options ieee } + +#include +#include +#include +#include +#include +#include +#include + +// Test std::from_chars floating-point conversions. + +#if __cpp_lib_to_chars >= 201611L +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) +void +test01() +{ + std::string s; + std::float64_t f64; + std::from_chars_result res; + + for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific, + std::chars_format::general, std::chars_format::hex }) + { + s = "Info"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); + VERIFY( std::isinf(f64) ); + VERIFY( res.ptr == s.data() + 3 ); + VERIFY( res.ec == std::errc{} ); + + s = "-INFIN"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); + VERIFY( std::isinf(f64) ); + VERIFY( f64 < 0 ); + VERIFY( res.ptr == s.data() + 4 ); + VERIFY( res.ec == std::errc{} ); + + s = "InFiNiTy aNd BeYoNd"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); + VERIFY( std::isinf(f64) ); + VERIFY( res.ptr == s.data() + 8 ); + VERIFY( res.ec == std::errc{} ); + + s = "nAn"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); + VERIFY( std::isnan(f64) ); + VERIFY( res.ptr == s.data() + 3 ); + VERIFY( res.ec == std::errc{} ); + + s = "-NAN()"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); + VERIFY( std::isnan(f64) ); + VERIFY( res.ptr == s.data() + s.length() ); + VERIFY( res.ec == std::errc{} ); + } +} + +void +test02() +{ + std::string s; + std::float64_t f64 = 1.0f64; + std::from_chars_result res; + + s = "0x123"; + res = std::from_chars(s.data(), s.data() + s.length(), f64); + VERIFY( f64 == 0.0f64 ); + VERIFY( res.ptr == s.data() + 1 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::fixed); + VERIFY( f64 == 0.0f64 ); + VERIFY( res.ptr == s.data() + 1 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::scientific); + VERIFY( f64 == 1.0f64 ); + VERIFY( res.ptr == s.data() ); + VERIFY( res.ec == std::errc::invalid_argument ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::general); + VERIFY( f64 == 0.0f64 ); + VERIFY( res.ptr == s.data() + 1 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::hex); + VERIFY( f64 == 0.0f64 ); + VERIFY( res.ptr == s.data() + 1 ); + VERIFY( res.ec == std::errc{} ); +} + +void +test03() +{ + std::string s; + std::float64_t f64 = 1.0f64; + std::from_chars_result res; + + s = "0.5e+2azzz"; + res = std::from_chars(s.data(), s.data() + s.length(), f64); + VERIFY( f64 == 0.5e+2f64 ); + VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); + VERIFY( res.ec == std::errc{} ); + + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::fixed); + VERIFY( f64 == 0.5f64 ); + VERIFY( res.ptr == s.data() + 3 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::scientific); + VERIFY( f64 == 0.5e+2f64 ); + VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0f64; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::general); + VERIFY( f64 == 0.5e+2f64 ); + VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); + VERIFY( res.ec == std::errc{} ); + + f64 = 1.0; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::hex); + VERIFY( f64 == 0x0.5Ep0f64 ); + VERIFY( res.ptr == s.data() + 4 ); + VERIFY( res.ec == std::errc{} ); + + s = "1.Ap-2zzz"; + res = std::from_chars(s.data(), s.data() + s.length(), f64, + std::chars_format::hex); + VERIFY( f64 == 0.40625f64 ); + VERIFY( res.ptr == s.data() + s.length() - 3 ); + VERIFY( res.ec == std::errc{} ); +} + +void +test04() +{ + // Huge input strings + std::string s(1000, '0'); + std::float64_t f64 = 1.0f64; + std::from_chars_result res; + res = std::from_chars(s.data(), s.data() + s.length(), f64); + VERIFY( res.ptr == s.data() + s.length() ); + VERIFY( res.ec == std::errc{} ); + VERIFY( f64 == 0.0f64 ); + + s += ".5"; + res = std::from_chars(s.data(), s.data() + s.length(), f64); + VERIFY( res.ptr == s.data() + s.length() ); + VERIFY( res.ec == std::errc{} ); + VERIFY( f64 == 0.5f64 ); + + s += "e2"; + auto len = s.length(); + s += std::string(1000, 'a'); + res = std::from_chars(s.data(), s.data() + s.length(), f64); + VERIFY( res.ptr == s.data() + len ); + VERIFY( res.ec == std::errc{} ); + VERIFY( f64 == 50.f64 ); +} +#endif + +using std::to_string; + +#ifdef __GLIBCXX_TYPE_INT_N_0 +std::string +to_string(unsigned __GLIBCXX_TYPE_INT_N_0 val) +{ + using Limits = std::numeric_limits; + std::string s(Limits::digits10+2, '0'); + for (auto iter = s.end(); val != 0; val /= 10) + *--iter = '0' + (val % 10); + return s; +} +#endif + +template +void +test_small_num() +{ + std::from_chars_result res; + FloatT flt; + + // Small integer values that are exactly representable + + for (int i = 0; i < 100; ++i) + { + std::string s = to_string(i); + int len = s.length(); + s += "123"; + const char* s1 = s.c_str(); + const char* s1_end = s1 + len; + + for (auto fmt : { std::chars_format::fixed, + std::chars_format::general, + std::chars_format::hex }) + { + if (fmt == std::chars_format::hex && i > 9) + continue; + + res = std::from_chars(s1, s1_end, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s1_end ); + VERIFY( flt == i ); + } + + if (i > 9) + continue; + + // Test single-digit integers with small exponents. + + const char s2[] = { '.', *s1, 'e', '0', '0', '0', '1' }; + const char* s2_end = s2 + sizeof(s2); + + const char s3[] = { *s1, '0', 'e', '-', '0', '0', '1' }; + const char* s3_end = s3 + sizeof(s3); + + for (auto fmt : { std::chars_format::scientific, + std::chars_format::general }) + { + res = std::from_chars(s2, s2_end, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s2_end ); + VERIFY( flt == i ); + + res = std::from_chars(s3, s3_end, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s3_end ); + VERIFY( flt == i ); + } + } +} + +void +test05() +{ +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + test_small_num(); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + test_small_num(); +#endif +#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + test_small_num(); +#endif +} + +template +void +test_max_mantissa() +{ + using Float_limits = std::numeric_limits; + using UInt_limits = std::numeric_limits; + + if (Float_limits::is_iec559 && Float_limits::digits < UInt_limits::digits) + { +#ifdef _GLIBCXX_USE_C99_MATH_TR1 + std::printf("Testing %d-bit float, using %zu-bit integer\n", + Float_limits::digits + (int)std::log2(Float_limits::max_exponent) + 1, + sizeof(UIntT) * __CHAR_BIT__); +#endif + + std::from_chars_result res; + FloatT flt; + + for (int i = 0; i < 10; ++i) + { + // (1 << digits) - 1 is the maximum value of the mantissa + const auto val = ((UIntT)1 << Float_limits::digits) - 1 - i; + std::string s = to_string(val); + auto len = s.length(); + s += "000"; // these should be ignored + for (auto fmt : { std::chars_format::fixed, + std::chars_format::general }) + { + res = std::from_chars(s.data(), s.data() + len, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s.data() + len ); + VERIFY( flt == val ); + } + s.resize(len); + const auto orig_len = len; + s += "e+000"; + len = s.length(); + s += "111"; + for (auto fmt : { std::chars_format::scientific, + std::chars_format::general }) + { + res = std::from_chars(s.data(), s.data() + len, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s.data() + len ); + VERIFY( flt == val ); + + std::string s2 = s.substr(0, len - 5); + s2.insert(s2.begin() + orig_len - 1, '.'); + s2 += "e000000000001"; + res = std::from_chars(s.data(), s.data() + len, flt, fmt); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s.data() + len ); + VERIFY( flt == val ); + } + } + } +} + +void +test06() +{ +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + test_max_mantissa(); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + test_max_mantissa(); +#endif +#if defined(__GLIBCXX_TYPE_INT_N_0) \ + && defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) + test_max_mantissa(); +#endif +} +#endif + +int +main() +{ +#if __cpp_lib_to_chars >= 201611L +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + test01(); + test02(); + test03(); + test04(); +#endif + test05(); + test06(); +#endif +} --- libstdc++-v3/testsuite/26_numerics/headers/cmath/nextafter_c++23.cc.jj 2022-10-19 11:24:54.748632989 +0200 +++ libstdc++-v3/testsuite/26_numerics/headers/cmath/nextafter_c++23.cc 2022-10-19 12:18:01.973503400 +0200 @@ -29,77 +29,77 @@ test () { using lim = std::numeric_limits; T t0 = std::nextafter(T(-0.0), T(2.0)); - VERIFY(t0 == lim::denorm_min()); + VERIFY( t0 == lim::denorm_min() ); T t1 = std::nextafter(T(), T(1.0)); - VERIFY(t1 == lim::denorm_min()); + VERIFY( t1 == lim::denorm_min() ); T t2 = std::nextafter(T(), T()); - VERIFY(t2 == T() && !std::signbit(t2)); + VERIFY( t2 == T() && !std::signbit(t2) ); T t3 = std::nextafter(lim::denorm_min(), T(-2.0)); - VERIFY(t3 == T() && !std::signbit(t3)); + VERIFY( t3 == T() && !std::signbit(t3) ); T t4 = std::nextafter(lim::min(), T(-0.0)); - VERIFY(std::fpclassify(t4) == FP_SUBNORMAL && t4 > T()); + VERIFY( std::fpclassify(t4) == FP_SUBNORMAL && t4 > T() ); T t5 = std::nextafter(t4, T(1.0)); - VERIFY(t5 == lim::min()); + VERIFY( t5 == lim::min() ); T t6 = std::nextafter(lim::min(), lim::infinity()); - VERIFY(std::fpclassify(t6) == FP_NORMAL && t6 > lim::min()); + VERIFY( std::fpclassify(t6) == FP_NORMAL && t6 > lim::min() ); T t7 = std::nextafter(t6, -lim::infinity()); - VERIFY(t7 == lim::min()); + VERIFY( t7 == lim::min() ); T t8 = std::nextafter(T(16.0), T(16.5)); - VERIFY(t8 > t7); + VERIFY( t8 > t7 ); T t9 = std::nextafter(t8, T(15.5)); - VERIFY(t9 == T(16.0)); + VERIFY( t9 == T(16.0) ); T t10 = std::nextafter(lim::max(), T(-0.5)); - VERIFY(std::fpclassify(t10) == FP_NORMAL && t10 < lim::max()); + VERIFY( std::fpclassify(t10) == FP_NORMAL && t10 < lim::max() ); T t11 = std::nextafter(t10, lim::infinity()); - VERIFY(t11 == lim::max()); + VERIFY( t11 == lim::max() ); T t12 = std::nextafter(t11, lim::infinity()); - VERIFY(std::fpclassify(t12) == FP_INFINITE && !std::signbit(t12)); + VERIFY( std::fpclassify(t12) == FP_INFINITE && !std::signbit(t12) ); T t13 = std::nextafter(lim::infinity(), t12); - VERIFY(t13 == t12); + VERIFY( t13 == t12 ); T t14 = std::nextafter(t13, T(1.0)); - VERIFY(t14 == lim::max()); + VERIFY( t14 == lim::max() ); T t15 = std::nextafter(lim::quiet_NaN(), T()); - VERIFY(std::fpclassify(t15) == FP_NAN); + VERIFY( std::fpclassify(t15) == FP_NAN ); T t16 = std::nextafter(T(17.0), lim::quiet_NaN()); - VERIFY(std::fpclassify(t16) == FP_NAN); + VERIFY( std::fpclassify(t16) == FP_NAN ); T t17 = std::nextafter(T(), T(-0.0)); - VERIFY(t17 == T() && std::signbit(t17)); + VERIFY( t17 == T() && std::signbit(t17) ); T t20 = std::nextafter(T(-0.0), T(-2.0)); - VERIFY(t20 == -lim::denorm_min()); + VERIFY( t20 == -lim::denorm_min() ); T t21 = std::nextafter(T(), T(-1.0)); - VERIFY(t21 == -lim::denorm_min()); + VERIFY( t21 == -lim::denorm_min() ); T t22 = std::nextafter(T(-0.0), T(-0.0)); - VERIFY(t22 == T() && std::signbit(t22)); + VERIFY( t22 == T() && std::signbit(t22) ); T t23 = std::nextafter(-lim::denorm_min(), T(2.0)); - VERIFY(t23 == T() && std::signbit(t23)); + VERIFY( t23 == T() && std::signbit(t23) ); T t24 = std::nextafter(-lim::min(), T()); - VERIFY(std::fpclassify(t24) == FP_SUBNORMAL && t24 < T()); + VERIFY( std::fpclassify(t24) == FP_SUBNORMAL && t24 < T() ); T t25 = std::nextafter(t24, T(-1.0)); - VERIFY(t25 == -lim::min()); + VERIFY( t25 == -lim::min() ); T t26 = std::nextafter(-lim::min(), -lim::infinity()); - VERIFY(std::fpclassify(t26) == FP_NORMAL && t26 < -lim::min()); + VERIFY( std::fpclassify(t26) == FP_NORMAL && t26 < -lim::min() ); T t27 = std::nextafter(t26, lim::infinity()); - VERIFY(t27 == -lim::min()); + VERIFY( t27 == -lim::min() ); T t28 = std::nextafter(T(-16.0), T(-16.5)); - VERIFY(t28 < t27); + VERIFY( t28 < t27 ); T t29 = std::nextafter(t28, T(-15.5)); - VERIFY(t29 == T(-16.0)); + VERIFY( t29 == T(-16.0) ); T t30 = std::nextafter(-lim::max(), T(0.5)); - VERIFY(std::fpclassify(t30) == FP_NORMAL && t30 > -lim::max()); + VERIFY( std::fpclassify(t30) == FP_NORMAL && t30 > -lim::max() ); T t31 = std::nextafter(t30, -lim::infinity()); - VERIFY(t31 == -lim::max()); + VERIFY( t31 == -lim::max() ); T t32 = std::nextafter(t31, -lim::infinity()); - VERIFY(std::fpclassify(t32) == FP_INFINITE && std::signbit(t32)); + VERIFY( std::fpclassify(t32) == FP_INFINITE && std::signbit(t32) ); T t33 = std::nextafter(-lim::infinity(), t32); - VERIFY(t33 == t32); + VERIFY( t33 == t32 ); T t34 = std::nextafter(t33, T(-1.0)); - VERIFY(t34 == -lim::max()); + VERIFY( t34 == -lim::max() ); T t35 = std::nextafter(-lim::quiet_NaN(), T()); - VERIFY(std::fpclassify(t35) == FP_NAN); + VERIFY( std::fpclassify(t35) == FP_NAN ); T t36 = std::nextafter(T(-17.0), lim::quiet_NaN()); - VERIFY(std::fpclassify(t36) == FP_NAN); + VERIFY( std::fpclassify(t36) == FP_NAN ); T t37 = std::nextafter(T(-0.0), T()); - VERIFY(t37 == T() && !std::signbit(t37)); + VERIFY( t37 == T() && !std::signbit(t37) ); } int --- libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc.jj 2022-10-19 11:23:51.000000000 +0200 +++ libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc 2022-10-19 11:36:26.760280020 +0200 @@ -15,6 +15,7 @@ // with this library; see the file COPYING3. If not see // . +// { dg-options "-std=gnu++2b" } // { dg-do link { target c++23 } } #include @@ -22,91 +23,91 @@ template __attribute__((__noipa__)) void -test_functions (T *p, int *q, long int *r, long long int *s) +test_functions(T *p, int *q, long int *r, long long int *s) { - p[0] = std::acos (p[0]); - p[1] = std::asin (p[1]); - p[2] = std::atan (p[2]); - p[3] = std::cos (p[3]); - p[4] = std::sin (p[4]); - p[5] = std::tan (p[5]); - p[6] = std::acosh (p[6]); - p[7] = std::asinh (p[7]); - p[8] = std::atanh (p[8]); - p[9] = std::cosh (p[9]); - p[10] = std::sinh (p[10]); - p[11] = std::tanh (p[11]); - p[12] = std::exp (p[12]); - p[13] = std::exp2 (p[13]); - p[14] = std::expm1 (p[14]); - p[15] = std::log (p[15]); - p[16] = std::log10 (p[16]); - p[17] = std::log1p (p[17]); - p[18] = std::log2 (p[18]); - p[19] = std::logb (p[19]); - p[20] = std::cbrt (p[20]); - p[21] = std::fabs (p[21]); - p[22] = std::sqrt (p[22]); - p[23] = std::erf (p[23]); - p[24] = std::erfc (p[24]); - p[25] = std::lgamma (p[25]); - p[26] = std::tgamma (p[26]); - p[27] = std::ceil (p[27]); - p[28] = std::floor (p[28]); - p[29] = std::nearbyint (p[29]); - p[30] = std::rint (p[30]); - p[31] = std::round (p[31]); - p[32] = std::trunc (p[32]); - p[33] = std::atan2 (p[33], p[100]); - p[34] = std::hypot (p[34], p[101]); - p[35] = std::pow (p[35], p[102]); - p[36] = std::fmod (p[36], p[103]); - p[37] = std::remainder (p[37], p[104]); - p[38] = std::copysign (p[38], p[105]); - p[39] = std::nextafter (p[39], p[106]); - p[40] = std::fdim (p[40], p[107]); - p[41] = std::fmax (p[41], p[108]); - p[42] = std::fmin (p[42], p[109]); - p[43] = std::atan2 (p[43], p[110]); - p[44] = std::frexp (p[44], q + 0); - q[1] = std::ilogb (p[45]); - p[46] = std::ldexp (p[46], q[2]); - p[47] = std::modf (p[47], p + 111); - p[48] = std::scalbn (p[48], q[3]); - p[49] = std::scalbln (p[49], r[0]); - p[50] = std::hypot (p[50], p[111], p[112]); - r[1] = std::lrint (p[51]); - s[0] = std::llrint (p[52]); - r[2] = std::lround (p[53]); - s[1] = std::llround (p[54]); - p[55] = std::remquo (p[55], p[113], q + 4); - p[56] = std::fma (p[56], p[114], p[115]); - p[57] = std::lerp (p[57], p[116], p[117]); - p[58] = std::assoc_laguerre (q[5], q[6], p[58]); - p[59] = std::assoc_legendre (q[7], q[8], p[59]); - p[60] = std::beta (p[60], p[118]); - p[61] = std::comp_ellint_1 (p[61]); - p[62] = std::comp_ellint_2 (p[62]); - p[63] = std::comp_ellint_3 (p[63], p[119]); - p[64] = std::cyl_bessel_i (p[64], p[120]); - p[65] = std::cyl_bessel_j (p[65], p[121]); - p[66] = std::cyl_bessel_k (p[66], p[122]); - p[67] = std::cyl_neumann (p[67], p[123]); - p[68] = std::ellint_1 (p[68], p[124]); - p[69] = std::ellint_2 (p[69], p[125]); - p[70] = std::ellint_3 (p[70], p[126], p[127]); - p[71] = std::expint (p[71]); - p[72] = std::hermite (q[9], p[72]); - p[73] = std::laguerre (q[10], p[73]); - p[74] = std::legendre (q[11], p[72]); - p[75] = std::riemann_zeta (p[75]); - p[76] = std::sph_bessel (q[12], p[76]); - p[77] = std::sph_legendre (q[13], q[14], p[77]); - p[78] = std::sph_neumann (q[15], p[78]); + p[0] = std::acos(p[0]); + p[1] = std::asin(p[1]); + p[2] = std::atan(p[2]); + p[3] = std::cos(p[3]); + p[4] = std::sin(p[4]); + p[5] = std::tan(p[5]); + p[6] = std::acosh(p[6]); + p[7] = std::asinh(p[7]); + p[8] = std::atanh(p[8]); + p[9] = std::cosh(p[9]); + p[10] = std::sinh(p[10]); + p[11] = std::tanh(p[11]); + p[12] = std::exp(p[12]); + p[13] = std::exp2(p[13]); + p[14] = std::expm1(p[14]); + p[15] = std::log(p[15]); + p[16] = std::log10(p[16]); + p[17] = std::log1p(p[17]); + p[18] = std::log2(p[18]); + p[19] = std::logb(p[19]); + p[20] = std::cbrt(p[20]); + p[21] = std::fabs(p[21]); + p[22] = std::sqrt(p[22]); + p[23] = std::erf(p[23]); + p[24] = std::erfc(p[24]); + p[25] = std::lgamma(p[25]); + p[26] = std::tgamma(p[26]); + p[27] = std::ceil(p[27]); + p[28] = std::floor(p[28]); + p[29] = std::nearbyint(p[29]); + p[30] = std::rint(p[30]); + p[31] = std::round(p[31]); + p[32] = std::trunc(p[32]); + p[33] = std::atan2(p[33], p[100]); + p[34] = std::hypot(p[34], p[101]); + p[35] = std::pow(p[35], p[102]); + p[36] = std::fmod(p[36], p[103]); + p[37] = std::remainder(p[37], p[104]); + p[38] = std::copysign(p[38], p[105]); + p[39] = std::nextafter(p[39], p[106]); + p[40] = std::fdim(p[40], p[107]); + p[41] = std::fmax(p[41], p[108]); + p[42] = std::fmin(p[42], p[109]); + p[43] = std::atan2(p[43], p[110]); + p[44] = std::frexp(p[44], q + 0); + q[1] = std::ilogb(p[45]); + p[46] = std::ldexp(p[46], q[2]); + p[47] = std::modf(p[47], p + 111); + p[48] = std::scalbn(p[48], q[3]); + p[49] = std::scalbln(p[49], r[0]); + p[50] = std::hypot(p[50], p[111], p[112]); + r[1] = std::lrint(p[51]); + s[0] = std::llrint(p[52]); + r[2] = std::lround(p[53]); + s[1] = std::llround(p[54]); + p[55] = std::remquo(p[55], p[113], q + 4); + p[56] = std::fma(p[56], p[114], p[115]); + p[57] = std::lerp(p[57], p[116], p[117]); + p[58] = std::assoc_laguerre(q[5], q[6], p[58]); + p[59] = std::assoc_legendre(q[7], q[8], p[59]); + p[60] = std::beta(p[60], p[118]); + p[61] = std::comp_ellint_1(p[61]); + p[62] = std::comp_ellint_2(p[62]); + p[63] = std::comp_ellint_3(p[63], p[119]); + p[64] = std::cyl_bessel_i(p[64], p[120]); + p[65] = std::cyl_bessel_j(p[65], p[121]); + p[66] = std::cyl_bessel_k(p[66], p[122]); + p[67] = std::cyl_neumann(p[67], p[123]); + p[68] = std::ellint_1(p[68], p[124]); + p[69] = std::ellint_2(p[69], p[125]); + p[70] = std::ellint_3(p[70], p[126], p[127]); + p[71] = std::expint(p[71]); + p[72] = std::hermite(q[9], p[72]); + p[73] = std::laguerre(q[10], p[73]); + p[74] = std::legendre(q[11], p[72]); + p[75] = std::riemann_zeta(p[75]); + p[76] = std::sph_bessel(q[12], p[76]); + p[77] = std::sph_legendre(q[13], q[14], p[77]); + p[78] = std::sph_neumann(q[15], p[78]); } int -main () +main() { int q[16] = {}; long int r[16] = {}; @@ -114,19 +115,19 @@ main () #if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) { std::float16_t p[128] = {}; - test_functions (p, q, r, s); + test_functions(p, q, r, s); } #endif #if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) { std::float32_t p[128] = {}; - test_functions (p, q, r, s); + test_functions(p, q, r, s); } #endif #if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) { std::float64_t p[128] = {}; - test_functions (p, q, r, s); + test_functions(p, q, r, s); } #endif #if defined(__STDCPP_FLOAT128_T__) \ @@ -134,13 +135,13 @@ main () || defined(_GLIBCXX_HAVE_FLOAT128_MATH)) { std::float128_t p[128] = {}; - test_functions (p, q, r, s); + test_functions(p, q, r, s); } #endif #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) { std::bfloat16_t p[128] = {}; - test_functions (p, q, r, s); + test_functions(p, q, r, s); } #endif } --- libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c++23.cc.jj 2022-10-18 11:35:55.000000000 +0200 +++ libstdc++-v3/testsuite/26_numerics/headers/cmath/c99_classification_macros_c++23.cc 2022-10-19 11:34:48.288610909 +0200 @@ -15,6 +15,7 @@ // with this library; see the file COPYING3. If not see // . +// { dg-options "-std=gnu++2b" } // { dg-do link { target c++23 } } // { dg-excess-errors "" { target uclibc } } Jakub