_ZSt21__to_chars_bfloat16_tPcS_fSt12chars_format;
_ZSt22__from_chars_float16_tPKcS0_RfSt12chars_format;
_ZSt23__from_chars_bfloat16_tPKcS0_RfSt12chars_format;
+ _ZSt8to_charsPcS_DF128_;
+ _ZSt8to_charsPcS_DF128_St12chars_format;
+ _ZSt8to_charsPcS_DF128_St12chars_formati;
+ _ZSt10from_charsPKcS0_RDF128_St12chars_format;
} GLIBCXX_3.4.30;
# Symbols in the support library (libsupc++) have their own tag.
__value = __val;
return __res;
}
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+ __extension__ from_chars_result
+ from_chars(const char* __first, const char* __last, __ieee128& __value,
+ chars_format __fmt = chars_format::general) noexcept;
+
+ inline from_chars_result
+ from_chars(const char* __first, const char* __last, _Float128& __value,
+ chars_format __fmt = chars_format::general) noexcept
+ {
+ __extension__ __ieee128 __val;
+ from_chars_result __res = from_chars(__first, __last, __val, __fmt);
+ if (__res.ec == errc{})
+ __value = __val;
+ return __res;
+ }
+#else
+ from_chars_result
+ from_chars(const char* __first, const char* __last, _Float128& __value,
+ chars_format __fmt = chars_format::general) noexcept;
+#endif
#endif
#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) \
return to_chars(__first, __last, static_cast<long double>(__value), __fmt,
__precision);
}
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+ __extension__ to_chars_result
+ to_chars(char* __first, char* __last, __float128 __value) noexcept;
+ __extension__ to_chars_result
+ to_chars(char* __first, char* __last, __float128 __value,
+ chars_format __fmt) noexcept;
+ __extension__ to_chars_result
+ to_chars(char* __first, char* __last, __float128 __value,
+ chars_format __fmt, int __precision) noexcept;
+
+ inline to_chars_result
+ to_chars(char* __first, char* __last, _Float128 __value) noexcept
+ {
+ __extension__
+ return to_chars(__first, __last, static_cast<__float128>(__value));
+ }
+ inline to_chars_result
+ to_chars(char* __first, char* __last, _Float128 __value,
+ chars_format __fmt) noexcept
+ {
+ __extension__
+ return to_chars(__first, __last, static_cast<__float128>(__value), __fmt);
+ }
+ inline to_chars_result
+ to_chars(char* __first, char* __last, _Float128 __value,
+ chars_format __fmt, int __precision) noexcept
+ {
+ __extension__
+ return to_chars(__first, __last, static_cast<__float128>(__value), __fmt,
+ __precision);
+ }
+#else
+ to_chars_result to_chars(char* __first, char* __last, _Float128 __value)
+ noexcept;
+ to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+ chars_format __fmt) noexcept;
+ to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+ chars_format __fmt, int __precision) noexcept;
+#endif
#endif
#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
#endif
// strtold for __ieee128
extern "C" __ieee128 __strtoieee128(const char*, char**);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+ && defined(__GLIBC_PREREQ)
+#define USE_STRTOF128_FOR_FROM_CHARS 1
+extern "C" _Float128 __strtof128(const char*, char**)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+ __attribute__((__weak__))
+#endif
+ __asm ("strtof128");
#endif
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
# ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
else if constexpr (is_same_v<T, __ieee128>)
tmpval = __strtoieee128(str, &endptr);
+# elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+ else if constexpr (is_same_v<T, _Float128>)
+ {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+ if (&__strtof128 == nullptr)
+ tmpval = _Float128(std::strtold(str, &endptr);
+ else
+#endif
+ tmpval = __strtof128(str, &endptr);
+ }
# endif
#else
tmpval = std::strtod(str, &endptr);
// fast_float doesn't support IEEE binary128 format, but we can use strtold.
return from_chars_strtod(first, last, value, fmt);
}
+#elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+from_chars_result
+from_chars(const char* first, const char* last, _Float128& value,
+ chars_format fmt) noexcept
+{
+ // fast_float doesn't support IEEE binary128 format, but we can use strtold.
+ return from_chars_strtod(first, last, value, fmt);
+}
#endif
#endif // USE_LIB_FAST_FLOAT || USE_STRTOD_FOR_FROM_CHARS
#endif
// sprintf for __ieee128
extern "C" int __sprintfieee128(char*, const char*, ...);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+ && defined(__GLIBC_PREREQ)
+extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+ __attribute__((__weak__))
+#endif
+ __asm ("strfromf128");
#endif
// This implementation crucially assumes float/double have the
#if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT && __FLT128_MANT_DIG__ == 113
// Define overloads of std::to_chars for __float128.
# define FLOAT128_TO_CHARS 1
-#endif
-
-#ifdef FLOAT128_TO_CHARS
using F128_type = __float128;
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+ && defined(__GLIBC_PREREQ)
+# define FLOAT128_TO_CHARS 1
+using F128_type = _Float128;
#else
using F128_type = void;
#endif
# ifdef FLOAT128_TO_CHARS
template<>
- struct floating_type_traits<__float128> : floating_type_traits_binary128
+ struct floating_type_traits<F128_type> : floating_type_traits_binary128
{ };
# endif
#endif
#pragma GCC diagnostic ignored "-Wabi"
template<typename T, typename... Extra>
inline int
- sprintf_ld(char* buffer, const char* format_string, T value, Extra... args)
+ sprintf_ld(char* buffer, size_t length __attribute__((unused)),
+ const char* format_string, T value, Extra... args)
{
int len;
fesetround(FE_TONEAREST); // We want round-to-nearest behavior.
#endif
+#ifdef FLOAT128_TO_CHARS
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
if constexpr (is_same_v<T, __ieee128>)
len = __sprintfieee128(buffer, format_string, args..., value);
else
+#else
+ if constexpr (is_same_v<T, _Float128>)
+ {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+ if (&__strfromf128 == nullptr)
+ len = sprintf(buffer, format_string, args..., (long double)value);
+ else
+#endif
+ if constexpr (sizeof...(args) == 0)
+ len = __strfromf128(buffer, length, "%.0f", value);
+ else
+ {
+ // strfromf128 unfortunately doesn't allow .*
+ char fmt[3 * sizeof(int) + 6];
+ sprintf(fmt, "%%.%d%c", args..., int(format_string[4]));
+ len = __strfromf128(buffer, length, fmt, value);
+ }
+ }
+ else
+#endif
#endif
len = sprintf(buffer, format_string, args..., value);
// can avoid this if we use sprintf to write all but the last
// digit, and carefully compute and write the last digit
// ourselves.
- char buffer[expected_output_length+1];
- const int output_length = sprintf_ld(buffer, "%.0Lf", value);
+ char buffer[expected_output_length + 1];
+ const int output_length = sprintf_ld(buffer,
+ expected_output_length + 1,
+ "%.0Lf", value);
__glibcxx_assert(output_length == expected_output_length);
memcpy(first, buffer, output_length);
return {first + output_length, errc{}};
__builtin_unreachable();
// Do the sprintf into the local buffer.
- char buffer[output_length_upper_bound+1];
+ char buffer[output_length_upper_bound + 1];
int output_length
- = sprintf_ld(buffer, output_specifier, value, effective_precision);
+ = sprintf_ld(buffer, output_length_upper_bound + 1, output_specifier,
+ value, effective_precision);
__glibcxx_assert(output_length <= output_length_upper_bound);
if (effective_precision > 0)
}
#ifdef FLOAT128_TO_CHARS
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
to_chars_result
to_chars(char* first, char* last, __float128 value) noexcept
{
{
return __floating_to_chars_precision(first, last, value, fmt, precision);
}
+#else
+to_chars_result
+to_chars(char* first, char* last, _Float128 value) noexcept
+{
+ return __floating_to_chars_shortest(first, last, value, chars_format{});
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt) noexcept
+{
+ return __floating_to_chars_shortest(first, last, value, fmt);
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt,
+ int precision) noexcept
+{
+ return __floating_to_chars_precision(first, last, value, fmt, precision);
+}
+#endif
#endif
// Entrypoints for 16-bit floats.
--- /dev/null
+// Copyright (C) 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2b" }
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target ieee_floats }
+// { dg-require-effective-target size32plus }
+// { dg-add-options ieee }
+
+#include <charconv>
+#include <stdfloat>
+#include <limits>
+#include <numbers>
+#include <testsuite_hooks.h>
+
+#if defined(__STDCPP_FLOAT128_T__) \
+ && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+ || defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+void
+test(std::chars_format fmt = std::chars_format{})
+{
+ std::float128_t tests[] = {
+// std::numeric_limits<std::float128_t>::denorm_min(),
+ std::numeric_limits<std::float128_t>::min(),
+ 0.0f128,
+ -42.0f128,
+ 1234.5678912345f128,
+ std::numbers::e_v<std::float128_t>,
+ std::numbers::log2e_v<std::float128_t>,
+ std::numbers::log10e_v<std::float128_t>,
+ std::numbers::pi_v<std::float128_t>,
+ std::numbers::inv_pi_v<std::float128_t>,
+ std::numbers::inv_sqrtpi_v<std::float128_t>,
+ std::numbers::ln2_v<std::float128_t>,
+ std::numbers::ln10_v<std::float128_t>,
+ std::numbers::sqrt2_v<std::float128_t>,
+ std::numbers::sqrt3_v<std::float128_t>,
+ std::numbers::inv_sqrt3_v<std::float128_t>,
+ std::numbers::egamma_v<std::float128_t>,
+ std::numbers::phi_v<std::float128_t>,
+ std::numeric_limits<std::float128_t>::max()
+ };
+ char str1[10000], str2[10000];
+ for (auto u : tests)
+ {
+ auto [ptr1, ec1] = std::to_chars(str1, str1 + sizeof(str1), u, fmt);
+ VERIFY( ec1 == std::errc() );
+// std::cout << i << ' ' << std::string_view (str1, ptr1) << '\n';
+ if (fmt == std::chars_format::fixed)
+ {
+ auto [ptr2, ec2] = std::to_chars(str2, str2 + (ptr1 - str1), u, fmt);
+ VERIFY( ec2 == std::errc() && ptr2 - str2 == ptr1 - str1 );
+ auto [ptr3, ec3] = std::to_chars(str2, str2 + (ptr1 - str1 - 1), u, fmt);
+ VERIFY( ec3 != std::errc() );
+ }
+ std::float128_t v;
+ auto [ptr4, ec4] = std::from_chars(str1, ptr1, v,
+ fmt == std::chars_format{}
+ ? std::chars_format::general : fmt);
+ VERIFY( ec4 == std::errc() && ptr4 == ptr1 );
+ VERIFY( u == v );
+
+ auto [ptr5, ec5] = std::to_chars(str1, str1 + sizeof(str1), u, fmt, 90);
+ VERIFY( ec5 == std::errc() );
+// std::cout << i << ' ' << std::string_view (str1, ptr5) << '\n';
+ v = 4.0f128;
+ auto [ptr6, ec6] = std::from_chars(str1, ptr5, v,
+ fmt == std::chars_format{}
+ ? std::chars_format::general : fmt);
+ VERIFY( ec6 == std::errc() && ptr6 == ptr5 );
+ if (fmt == std::chars_format::fixed && u > 0.0f128 && u < 0.000001f128)
+ VERIFY( v == 0.0 );
+ else
+ VERIFY( u == v );
+ }
+}
+#endif
+
+int
+main()
+{
+#if defined(__STDCPP_FLOAT128_T__) \
+ && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+ || defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+ test();
+ test(std::chars_format::fixed);
+ test(std::chars_format::scientific);
+ test(std::chars_format::general);
+ test(std::chars_format::hex);
+#endif
+}