diff options
4 files changed, 223 insertions, 9 deletions
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath index 81635a0..555d644 100644 --- a/libstdc++-v3/include/c_global/cmath +++ b/libstdc++-v3/include/c_global/cmath @@ -2755,7 +2755,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION nearbyint(_Float16 __x) { return _Float16(__builtin_nearbyintf(__x)); } - // nextafter not implemented so far. + inline _Float16 + nextafter(_Float16 __x, _Float16 __y) + { +#ifdef __INT16_TYPE__ + using __float16_int_type = __INT16_TYPE__; +#else + using __float16_int_type = short int; +#endif + __float16_int_type __hx, __hy, __ix, __iy; + __builtin_memcpy(&__hx, &__x, sizeof(__x)); + __builtin_memcpy(&__hy, &__y, sizeof(__x)); + __ix = __hx & 0x7fff; // |x| + __iy = __hy & 0x7fff; // |y| + if (__ix > 0x7c00 || __iy > 0x7c00) // x or y is NaN + return __x + __y; + if (__x == __y) + return __y; // x == y, return y + if (__ix == 0) // x == 0 + { + __hy = (__hy & 0x8000) | 1; // return +-__FLT16_DENORM_MIN__ + __builtin_memcpy(&__x, &__hy, sizeof(__x)); + __builtin_nextafterf(0.0f, 1.0f); // raise underflow + return __x; + } + if (__hx >= 0) // x > 0 + { + if (__hx > __hy) // x > y, x -= ulp + --__hx; + else // x < y, x += ulp + ++__hx; + } + else // x < 0 + { + if (__hy >= 0 || __hx > __hy) // x < y, x -= ulp + --__hx; + else // x > y, x += ulp + ++__hx; + } + __hy = __hx & 0x7c00; + if (__hy >= 0x7c00) + __builtin_nextafterf(__FLT_MAX__, __builtin_inff()); // overflow + else if (__hy < 0x0400) + __builtin_nextafterf(__FLT_MIN__, 0.0f); // underflow + __builtin_memcpy(&__x, &__hx, sizeof(__x)); + return __x; + } constexpr _Float16 remainder(_Float16 __x, _Float16 __y) @@ -3426,7 +3471,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION nearbyint(__gnu_cxx::__bfloat16_t __x) { return __gnu_cxx::__bfloat16_t(__builtin_nearbyintf(__x)); } - // nextafter not implemented so far. + inline __gnu_cxx::__bfloat16_t + nextafter(__gnu_cxx::__bfloat16_t __x, __gnu_cxx::__bfloat16_t __y) + { +#ifdef __INT16_TYPE__ + using __bfloat16_int_type = __INT16_TYPE__; +#else + using __bfloat16_int_type = short int; +#endif + __bfloat16_int_type __hx, __hy, __ix, __iy; + __builtin_memcpy(&__hx, &__x, sizeof(__x)); + __builtin_memcpy(&__hy, &__y, sizeof(__x)); + __ix = __hx & 0x7fff; // |x| + __iy = __hy & 0x7fff; // |y| + if (__ix > 0x7f80 || __iy > 0x7f80) // x or y is NaN + return __x + __y; + if (__x == __y) + return __y; // x == y, return y + if (__ix == 0) // x == 0 + { + __hy = (__hy & 0x8000) | 1; // return +-__BFLT16_DENORM_MIN__ + __builtin_memcpy(&__x, &__hy, sizeof(__x)); + __builtin_nextafterf(0.0f, 1.0f); // raise underflow + return __x; + } + if (__hx >= 0) // x > 0 + { + if (__hx > __hy) // x > y, x -= ulp + --__hx; + else // x < y, x += ulp + ++__hx; + } + else // x < 0 + { + if (__hy >= 0 || __hx > __hy) // x < y, x -= ulp + --__hx; + else // x > y, x += ulp + ++__hx; + } + __hy = __hx & 0x7f80; + if (__hy >= 0x7f80) + __builtin_nextafterf(__FLT_MAX__, __builtin_inff()); // overflow + else if (__hy < 0x0080) + __builtin_nextafterf(__FLT_MIN__, 0.0f); // underflow + __builtin_memcpy(&__x, &__hx, sizeof(__x)); + return __x; + } constexpr __gnu_cxx::__bfloat16_t remainder(__gnu_cxx::__bfloat16_t __x, __gnu_cxx::__bfloat16_t __y) diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits index 61b6c3b..9dde9f3 100644 --- a/libstdc++-v3/include/std/limits +++ b/libstdc++-v3/include/std/limits @@ -1890,7 +1890,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #undef __glibcxx_long_double_traps #undef __glibcxx_long_double_tinyness_before -#if __cplusplus > 202202L +#if __cplusplus > 202002L #define __glibcxx_concat3_(P,M,S) P ## M ## S #define __glibcxx_concat3(P,M,S) __glibcxx_concat3_ (P,M,S) @@ -1924,8 +1924,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static constexpr bool is_signed = true; \ static constexpr bool is_integer = false; \ static constexpr bool is_exact = false; \ - static constexpr int radix \ - = __glibcxx_concat3 (__FLT, BITSIZE, _RADIX__); \ + static constexpr int radix = __FLT_RADIX__; \ \ static constexpr _Float##BITSIZE \ epsilon() noexcept \ @@ -2023,7 +2022,7 @@ __glibcxx_float_n(128) static constexpr bool is_signed = true; static constexpr bool is_integer = false; static constexpr bool is_exact = false; - static constexpr int radix = __BFLT16_RADIX__; + static constexpr int radix = __FLT_RADIX__; static constexpr __gnu_cxx::__bfloat16_t epsilon() noexcept diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc index bc88662..190f8d1 100644 --- a/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc +++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_std_c++23.cc @@ -63,7 +63,7 @@ test_functions (T *p, int *q, long int *r, long long int *s) 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[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]); @@ -102,13 +102,13 @@ test_functions (T *p, int *q, long int *r, long long int *s) 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], q[16], p[78]); + p[78] = std::sph_neumann (q[15], p[78]); } int main () { - int q[17] = {}; + int q[16] = {}; long int r[16] = {}; long long int s[16] = {}; #if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/nextafter_c++23.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/nextafter_c++23.cc new file mode 100644 index 0000000..45aa3b7 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/nextafter_c++23.cc @@ -0,0 +1,125 @@ +// 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 } } + +#include <stdfloat> +#include <cmath> +#include <limits> +#include <testsuite_hooks.h> + +template <typename T> +void +test () +{ + using lim = std::numeric_limits<T>; + T t0 = std::nextafter(T(-0.0), T(2.0)); + VERIFY(t0 == lim::denorm_min()); + T t1 = std::nextafter(T(), T(1.0)); + VERIFY(t1 == lim::denorm_min()); + T t2 = std::nextafter(T(), T()); + VERIFY(t2 == T() && !std::signbit(t2)); + T t3 = std::nextafter(lim::denorm_min(), T(-2.0)); + VERIFY(t3 == T() && !std::signbit(t3)); + T t4 = std::nextafter(lim::min(), T(-0.0)); + VERIFY(std::fpclassify(t4) == FP_SUBNORMAL && t4 > T()); + T t5 = std::nextafter(t4, T(1.0)); + VERIFY(t5 == lim::min()); + T t6 = std::nextafter(lim::min(), lim::infinity()); + VERIFY(std::fpclassify(t6) == FP_NORMAL && t6 > lim::min()); + T t7 = std::nextafter(t6, -lim::infinity()); + VERIFY(t7 == lim::min()); + T t8 = std::nextafter(T(16.0), T(16.5)); + VERIFY(t8 > t7); + T t9 = std::nextafter(t8, T(15.5)); + VERIFY(t9 == T(16.0)); + T t10 = std::nextafter(lim::max(), T(-0.5)); + VERIFY(std::fpclassify(t10) == FP_NORMAL && t10 < lim::max()); + T t11 = std::nextafter(t10, lim::infinity()); + VERIFY(t11 == lim::max()); + T t12 = std::nextafter(t11, lim::infinity()); + VERIFY(std::fpclassify(t12) == FP_INFINITE && !std::signbit(t12)); + T t13 = std::nextafter(lim::infinity(), t12); + VERIFY(t13 == t12); + T t14 = std::nextafter(t13, T(1.0)); + VERIFY(t14 == lim::max()); + T t15 = std::nextafter(lim::quiet_NaN(), T()); + VERIFY(std::fpclassify(t15) == FP_NAN); + T t16 = std::nextafter(T(17.0), lim::quiet_NaN()); + VERIFY(std::fpclassify(t16) == FP_NAN); + T t17 = std::nextafter(T(), T(-0.0)); + VERIFY(t17 == T() && std::signbit(t17)); + T t20 = std::nextafter(T(-0.0), T(-2.0)); + VERIFY(t20 == -lim::denorm_min()); + T t21 = std::nextafter(T(), T(-1.0)); + VERIFY(t21 == -lim::denorm_min()); + T t22 = std::nextafter(T(-0.0), T(-0.0)); + VERIFY(t22 == T() && std::signbit(t22)); + T t23 = std::nextafter(-lim::denorm_min(), T(2.0)); + VERIFY(t23 == T() && std::signbit(t23)); + T t24 = std::nextafter(-lim::min(), T()); + VERIFY(std::fpclassify(t24) == FP_SUBNORMAL && t24 < T()); + T t25 = std::nextafter(t24, T(-1.0)); + VERIFY(t25 == -lim::min()); + T t26 = std::nextafter(-lim::min(), -lim::infinity()); + VERIFY(std::fpclassify(t26) == FP_NORMAL && t26 < -lim::min()); + T t27 = std::nextafter(t26, lim::infinity()); + VERIFY(t27 == -lim::min()); + T t28 = std::nextafter(T(-16.0), T(-16.5)); + VERIFY(t28 < t27); + T t29 = std::nextafter(t28, T(-15.5)); + VERIFY(t29 == T(-16.0)); + T t30 = std::nextafter(-lim::max(), T(0.5)); + VERIFY(std::fpclassify(t30) == FP_NORMAL && t30 > -lim::max()); + T t31 = std::nextafter(t30, -lim::infinity()); + VERIFY(t31 == -lim::max()); + T t32 = std::nextafter(t31, -lim::infinity()); + VERIFY(std::fpclassify(t32) == FP_INFINITE && std::signbit(t32)); + T t33 = std::nextafter(-lim::infinity(), t32); + VERIFY(t33 == t32); + T t34 = std::nextafter(t33, T(-1.0)); + VERIFY(t34 == -lim::max()); + T t35 = std::nextafter(-lim::quiet_NaN(), T()); + VERIFY(std::fpclassify(t35) == FP_NAN); + T t36 = std::nextafter(T(-17.0), lim::quiet_NaN()); + VERIFY(std::fpclassify(t36) == FP_NAN); + T t37 = std::nextafter(T(-0.0), T()); + VERIFY(t37 == T() && !std::signbit(t37)); +} + +int +main () +{ +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + test <std::float16_t>(); +#endif +#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + test <std::float32_t>(); +#endif +#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + test <std::float64_t>(); +#endif +#if defined(__STDCPP_FLOAT128_T__) \ + && (defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY128) \ + || defined(_GLIBCXX_HAVE_FLOAT128_MATH)) + test <std::float128_t>(); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + test <std::bfloat16_t>(); +#endif +} |