diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -488,6 +488,7 @@ __math/hypot.h __math/inverse_hyperbolic_functions.h __math/inverse_trigonometric_functions.h + __math/lerp.h __math/logarithms.h __math/min_max.h __math/remainder.h diff --git a/libcxx/include/__math/abs.h b/libcxx/include/__math/abs.h --- a/libcxx/include/__math/abs.h +++ b/libcxx/include/__math/abs.h @@ -39,6 +39,23 @@ return __builtin_fabs((double)__x); } +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT { + return __builtin_fabsf(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT { + return __builtin_fabs(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT { + return __builtin_fabsl(__x); +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT { + return __builtin_fabs(static_cast(__x)); +} + } // namespace __math _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__math/copysign.h b/libcxx/include/__math/copysign.h --- a/libcxx/include/__math/copysign.h +++ b/libcxx/include/__math/copysign.h @@ -38,6 +38,27 @@ return ::__builtin_copysign(__x, __y); } +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT { + return __builtin_copysignf(__x, __y); +} + +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT { + return __builtin_copysign(__x, __y); +} + +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double +__constexpr_copysign(long double __x, long double __y) _NOEXCEPT { + return __builtin_copysignl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI __promote<_A1, _A2>::type +__constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT { + typedef typename __promote<_A1, _A2>::type __result_type; + static_assert((!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value)), ""); + return __builtin_copysign((__result_type)__x, (__result_type)__y); +} + } // namespace __math _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__math/exponential_functions.h b/libcxx/include/__math/exponential_functions.h --- a/libcxx/include/__math/exponential_functions.h +++ b/libcxx/include/__math/exponential_functions.h @@ -10,10 +10,13 @@ #define _LIBCPP___MATH_EXPONENTIAL_FUNCTIONS_H #include <__config> +#include <__math/traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_integral.h> #include <__type_traits/promote.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -143,6 +146,47 @@ return __builtin_scalbn((double)__x, __y); } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) { +#if !__has_constexpr_builtin(__builtin_scalbln) + if (__libcpp_is_constant_evaluated()) { + if (__x == _Tp(0)) + return __x; + + if (__math::__constexpr_isinf(__x)) + return __x; + + if (__exp == _Tp(0)) + return __x; + + if (__math::__constexpr_isnan(__x)) + return numeric_limits<_Tp>::quiet_NaN(); + + _Tp __mult(1); + if (__exp > 0) { + __mult = numeric_limits<_Tp>::radix; + --__exp; + } else { + ++__exp; + __exp = -__exp; + __mult /= numeric_limits<_Tp>::radix; + } + + while (__exp > 0) { + if (!(__exp & 1)) { + __mult *= __mult; + __exp >>= 1; + } else { + __x *= __mult; + --__exp; + } + } + return __x; + } +#endif // !__has_constexpr_builtin(__builtin_scalbln) + return __builtin_scalbn(__x, __exp); +} + // pow inline _LIBCPP_HIDE_FROM_ABI float pow(float __x, float __y) _NOEXCEPT { return __builtin_powf(__x, __y); } diff --git a/libcxx/include/__math/hypot.h b/libcxx/include/__math/hypot.h --- a/libcxx/include/__math/hypot.h +++ b/libcxx/include/__math/hypot.h @@ -10,6 +10,7 @@ #define _LIBCPP___MATH_HYPOT_H #include <__config> +#include <__math/roots.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_arithmetic.h> #include <__type_traits/promote.h> @@ -40,6 +41,30 @@ return __math::hypot((__result_type)__x, (__result_type)__y); } +#if _LIBCPP_STD_VER >= 17 +inline _LIBCPP_HIDE_FROM_ABI float hypot(float __x, float __y, float __z) { + return __math::sqrt(__x * __x + __y * __y + __z * __z); +} +inline _LIBCPP_HIDE_FROM_ABI double hypot(double __x, double __y, double __z) { + return __math::sqrt(__x * __x + __y * __y + __z * __z); +} +inline _LIBCPP_HIDE_FROM_ABI long double hypot(long double __x, long double __y, long double __z) { + return __math::sqrt(__x * __x + __y * __y + __z * __z); +} + +template ::value && is_arithmetic<_A2>::value && is_arithmetic<_A3>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI __promote<_A1, _A2, _A3>::type hypot(_A1 __lcpp_x, _A2 __lcpp_y, _A3 __lcpp_z) _NOEXCEPT { + typedef typename __promote<_A1, _A2, _A3>::type __result_type; + static_assert((!(is_same<_A1, __result_type>::value && is_same<_A2, __result_type>::value && + is_same<_A3, __result_type>::value)), + ""); + return __math::hypot((__result_type)__lcpp_x, (__result_type)__lcpp_y, (__result_type)__lcpp_z); +} +#endif + } // namespace __math _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__math/lerp.h b/libcxx/include/__math/lerp.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__math/lerp.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_LERP_H +#define _LIBCPP___MATH_LERP_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +#if _LIBCPP_STD_VER >= 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept { + if ((__a <= 0 && __b >= 0) || (__a >= 0 && __b <= 0)) + return __t * __b + (1 - __t) * __a; + + if (__t == 1) + return __b; + const _Fp __x = __a + __t * (__b - __a); + if ((__t > 1) == (__b > __a)) + return __b < __x ? __x : __b; + else + return __x < __b ? __x : __b; +} + +_LIBCPP_HIDE_FROM_ABI constexpr float lerp(float __a, float __b, float __t) _NOEXCEPT { return __lerp(__a, __b, __t); } + +_LIBCPP_HIDE_FROM_ABI constexpr double lerp(double __a, double __b, double __t) _NOEXCEPT { + return __lerp(__a, __b, __t); +} + +_LIBCPP_HIDE_FROM_ABI constexpr long double lerp(long double __a, long double __b, long double __t) _NOEXCEPT { + return __lerp(__a, __b, __t); +} + +template ::value && is_arithmetic<_A2>::value && is_arithmetic<_A3>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr __promote<_A1, _A2, _A3>::type lerp(_A1 __a, _A2 __b, _A3 __t) noexcept { + typedef typename __promote<_A1, _A2, _A3>::type __result_type; + static_assert(!( + _IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value && _IsSame<_A3, __result_type>::value)); + return __math::__lerp((__result_type)__a, (__result_type)__b, (__result_type)__t); +} +#endif // _LIBCPP_STD_VER >= 20 + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_LERP_H diff --git a/libcxx/include/__math/logarithms.h b/libcxx/include/__math/logarithms.h --- a/libcxx/include/__math/logarithms.h +++ b/libcxx/include/__math/logarithms.h @@ -10,8 +10,12 @@ #define _LIBCPP___MATH_LOGARITHMS_H #include <__config> +#include <__math/abs.h> +#include <__math/traits.h> #include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_integral.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -69,6 +73,33 @@ return __builtin_ilogb((double)__x); } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) { +#if !__has_constexpr_builtin(__builtin_logb) + if (__libcpp_is_constant_evaluated()) { + if (__x == _Tp(0)) { + // raise FE_DIVBYZERO + return -numeric_limits<_Tp>::infinity(); + } + + if (__math::__constexpr_isinf(__x)) + return numeric_limits<_Tp>::infinity(); + + if (__math::__constexpr_isnan(__x)) + return numeric_limits<_Tp>::quiet_NaN(); + + __x = __math::__constexpr_fabs(__x); + unsigned long long __exp = 0; + while (__x >= numeric_limits<_Tp>::radix) { + __x /= numeric_limits<_Tp>::radix; + __exp += 1; + } + return _Tp(__exp); + } +#endif // !__has_constexpr_builtin(__builtin_logb) + return __builtin_logb(__x); +} + // log1p inline _LIBCPP_HIDE_FROM_ABI float log1p(float __x) _NOEXCEPT { return __builtin_log1pf(__x); } diff --git a/libcxx/include/__math/min_max.h b/libcxx/include/__math/min_max.h --- a/libcxx/include/__math/min_max.h +++ b/libcxx/include/__math/min_max.h @@ -10,8 +10,10 @@ #define _LIBCPP___MATH_MIN_MAX_H #include <__config> +#include <__math/traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/promote.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -44,6 +46,53 @@ return __math::fmax((__result_type)__x, (__result_type)__y); } +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmaxf) + if (__libcpp_is_constant_evaluated()) { + if (__math::__constexpr_isnan(__x)) + return __y; + if (__math::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmaxf(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmax) + if (__libcpp_is_constant_evaluated()) { + if (__math::__constexpr_isnan(__x)) + return __y; + if (__math::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmax(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double +__constexpr_fmax(long double __x, long double __y) _NOEXCEPT { +#if !__has_constexpr_builtin(__builtin_fmaxl) + if (__libcpp_is_constant_evaluated()) { + if (__math::__constexpr_isnan(__x)) + return __y; + if (__math::__constexpr_isnan(__y)) + return __x; + return __x < __y ? __y : __x; + } +#endif + return __builtin_fmaxl(__x, __y); +} + +template ::value && is_arithmetic<_Up>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type +__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT { + using __result_type = typename __promote<_Tp, _Up>::type; + return __math::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y)); +} + // fmin _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI float fmin(float __x, float __y) _NOEXCEPT { diff --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h --- a/libcxx/include/__math/traits.h +++ b/libcxx/include/__math/traits.h @@ -46,15 +46,20 @@ // isfinite template ::value && numeric_limits<_A1>::has_infinity, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1 __x) _NOEXCEPT { +_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __constexpr_isfinite(_A1 __x) _NOEXCEPT { return __builtin_isfinite((typename __promote<_A1>::type)__x); } template ::value && !numeric_limits<_A1>::has_infinity, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1) _NOEXCEPT { +_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __constexpr_isfinite(_A1) _NOEXCEPT { return true; } +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool isfinite(_A1 __x) _NOEXCEPT { + return __math::__constexpr_isfinite(__x); +} + // isinf template ::value && numeric_limits<_A1>::has_infinity, int> = 0> @@ -82,6 +87,11 @@ } #endif +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __constexpr_isinf(_A1 __lcpp_x) _NOEXCEPT { + return __builtin_isinf(__lcpp_x); +} + // isnan template ::value, int> = 0> @@ -109,6 +119,11 @@ } #endif +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __constexpr_isnan(_A1 __lcpp_x) _NOEXCEPT { + return __builtin_isnan(__lcpp_x); +} + // isnormal template ::value, int> = 0> diff --git a/libcxx/include/cmath b/libcxx/include/cmath --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -306,13 +306,7 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__config> -#include <__type_traits/enable_if.h> -#include <__type_traits/is_arithmetic.h> -#include <__type_traits/is_constant_evaluated.h> -#include <__type_traits/is_floating_point.h> -#include <__type_traits/is_same.h> -#include <__type_traits/promote.h> -#include <__type_traits/remove_cv.h> +#include <__math/lerp.h> #include #include @@ -544,287 +538,17 @@ using ::tgammal _LIBCPP_USING_IF_EXISTS; using ::truncl _LIBCPP_USING_IF_EXISTS; -#if _LIBCPP_STD_VER >= 17 -inline _LIBCPP_INLINE_VISIBILITY float hypot( float __x, float __y, float __z ) { return sqrt(__x*__x + __y*__y + __z*__z); } -inline _LIBCPP_INLINE_VISIBILITY double hypot( double __x, double __y, double __z ) { return sqrt(__x*__x + __y*__y + __z*__z); } -inline _LIBCPP_INLINE_VISIBILITY long double hypot( long double __x, long double __y, long double __z ) { return sqrt(__x*__x + __y*__y + __z*__z); } - -template -inline _LIBCPP_INLINE_VISIBILITY -typename enable_if_t -< - is_arithmetic<_A1>::value && - is_arithmetic<_A2>::value && - is_arithmetic<_A3>::value, - __promote<_A1, _A2, _A3> ->::type -hypot(_A1 __lcpp_x, _A2 __lcpp_y, _A3 __lcpp_z) _NOEXCEPT -{ - typedef typename __promote<_A1, _A2, _A3>::type __result_type; - static_assert((!(is_same<_A1, __result_type>::value && - is_same<_A2, __result_type>::value && - is_same<_A3, __result_type>::value)), ""); - return std::hypot((__result_type)__lcpp_x, (__result_type)__lcpp_y, (__result_type)__lcpp_z); -} -#endif - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isnan(_A1 __lcpp_x) _NOEXCEPT -{ -#if __has_builtin(__builtin_isnan) - return __builtin_isnan(__lcpp_x); -#else - return isnan(__lcpp_x); -#endif -} - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isnan(_A1 __lcpp_x) _NOEXCEPT -{ - return std::isnan(__lcpp_x); -} - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isinf(_A1 __lcpp_x) _NOEXCEPT -{ -#if __has_builtin(__builtin_isinf) - return __builtin_isinf(__lcpp_x); -#else - return isinf(__lcpp_x); -#endif -} - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isinf(_A1 __lcpp_x) _NOEXCEPT -{ - return std::isinf(__lcpp_x); -} - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isfinite(_A1 __lcpp_x) _NOEXCEPT -{ -#if __has_builtin(__builtin_isfinite) - return __builtin_isfinite(__lcpp_x); -#else - return isfinite(__lcpp_x); -#endif -} - -template -_LIBCPP_INLINE_VISIBILITY -_LIBCPP_CONSTEXPR typename enable_if::value, bool>::type -__constexpr_isfinite(_A1 __lcpp_x) _NOEXCEPT -{ - return __builtin_isfinite(__lcpp_x); -} - -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI float __constexpr_copysign(float __x, float __y) _NOEXCEPT { - return __builtin_copysignf(__x, __y); -} - -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI double __constexpr_copysign(double __x, double __y) _NOEXCEPT { - return __builtin_copysign(__x, __y); -} - -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI long double -__constexpr_copysign(long double __x, long double __y) _NOEXCEPT { - return __builtin_copysignl(__x, __y); -} - -template -_LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI - typename std::__enable_if_t::value && std::is_arithmetic<_A2>::value, - std::__promote<_A1, _A2> >::type - __constexpr_copysign(_A1 __x, _A2 __y) _NOEXCEPT { - typedef typename std::__promote<_A1, _A2>::type __result_type; - static_assert((!(std::_IsSame<_A1, __result_type>::value && std::_IsSame<_A2, __result_type>::value)), ""); - return __builtin_copysign((__result_type)__x, (__result_type)__y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float __constexpr_fabs(float __x) _NOEXCEPT { - return __builtin_fabsf(__x); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(double __x) _NOEXCEPT { - return __builtin_fabs(__x); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double __constexpr_fabs(long double __x) _NOEXCEPT { - return __builtin_fabsl(__x); -} - -template ::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double __constexpr_fabs(_Tp __x) _NOEXCEPT { - return __builtin_fabs(static_cast(__x)); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmaxf) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmaxf(__x, __y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmax) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmax(__x, __y); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double -__constexpr_fmax(long double __x, long double __y) _NOEXCEPT { -#if !__has_constexpr_builtin(__builtin_fmaxl) - if (__libcpp_is_constant_evaluated()) { - if (std::__constexpr_isnan(__x)) - return __y; - if (std::__constexpr_isnan(__y)) - return __x; - return __x < __y ? __y : __x; - } -#endif - return __builtin_fmaxl(__x, __y); -} - -template ::value && is_arithmetic<_Up>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type -__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT { - using __result_type = typename __promote<_Tp, _Up>::type; - return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y)); -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) { -#if !__has_constexpr_builtin(__builtin_logb) - if (__libcpp_is_constant_evaluated()) { - if (__x == _Tp(0)) { - // raise FE_DIVBYZERO - return -numeric_limits<_Tp>::infinity(); - } - - if (std::__constexpr_isinf(__x)) - return numeric_limits<_Tp>::infinity(); - - if (std::__constexpr_isnan(__x)) - return numeric_limits<_Tp>::quiet_NaN(); - - __x = std::__constexpr_fabs(__x); - unsigned long long __exp = 0; - while (__x >= numeric_limits<_Tp>::radix) { - __x /= numeric_limits<_Tp>::radix; - __exp += 1; - } - return _Tp(__exp); - } -#endif // !__has_constexpr_builtin(__builtin_logb) - return __builtin_logb(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) { -#if !__has_constexpr_builtin(__builtin_scalbln) - if (__libcpp_is_constant_evaluated()) { - if (__x == _Tp(0)) - return __x; - - if (std::__constexpr_isinf(__x)) - return __x; - - if (__exp == _Tp(0)) - return __x; - - if (std::__constexpr_isnan(__x)) - return numeric_limits<_Tp>::quiet_NaN(); - - _Tp __mult(1); - if (__exp > 0) { - __mult = numeric_limits<_Tp>::radix; - --__exp; - } else { - ++__exp; - __exp = -__exp; - __mult /= numeric_limits<_Tp>::radix; - } - - while (__exp > 0) { - if (!(__exp & 1)) { - __mult *= __mult; - __exp >>= 1; - } else { - __x *= __mult; - --__exp; - } - } - return __x; - } -#endif // !__has_constexpr_builtin(__builtin_scalbln) - return __builtin_scalbn(__x, __exp); -} - -#if _LIBCPP_STD_VER >= 20 -template -_LIBCPP_HIDE_FROM_ABI constexpr -_Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept { - if ((__a <= 0 && __b >= 0) || (__a >= 0 && __b <= 0)) - return __t * __b + (1 - __t) * __a; - - if (__t == 1) return __b; - const _Fp __x = __a + __t * (__b - __a); - if ((__t > 1) == (__b > __a)) - return __b < __x ? __x : __b; - else - return __x < __b ? __x : __b; -} - -_LIBCPP_HIDE_FROM_ABI constexpr float -lerp(float __a, float __b, float __t) _NOEXCEPT { return __lerp(__a, __b, __t); } - -_LIBCPP_HIDE_FROM_ABI constexpr double -lerp(double __a, double __b, double __t) _NOEXCEPT { return __lerp(__a, __b, __t); } - -_LIBCPP_HIDE_FROM_ABI constexpr long double -lerp(long double __a, long double __b, long double __t) _NOEXCEPT { return __lerp(__a, __b, __t); } - -template -inline _LIBCPP_HIDE_FROM_ABI -constexpr typename enable_if_t -< - is_arithmetic<_A1>::value && - is_arithmetic<_A2>::value && - is_arithmetic<_A3>::value, - __promote<_A1, _A2, _A3> ->::type -lerp(_A1 __a, _A2 __b, _A3 __t) noexcept -{ - typedef typename __promote<_A1, _A2, _A3>::type __result_type; - static_assert(!(_IsSame<_A1, __result_type>::value && - _IsSame<_A2, __result_type>::value && - _IsSame<_A3, __result_type>::value)); - return std::__lerp((__result_type)__a, (__result_type)__b, (__result_type)__t); -} -#endif // _LIBCPP_STD_VER >= 20 +using __math::lerp; + +// TODO: don't import these declarations into std:: +using __math::__constexpr_copysign; +using __math::__constexpr_fabs; +using __math::__constexpr_fmax; +using __math::__constexpr_isfinite; +using __math::__constexpr_isinf; +using __math::__constexpr_isnan; +using __math::__constexpr_logb; +using __math::__constexpr_scalbn; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp b/libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp --- a/libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp +++ b/libcxx/test/std/depr/depr.c.headers/math_h.pass.cpp @@ -869,6 +869,9 @@ void operator()() { ASSERT_SAME_TYPE(decltype(::fma(T(), U(), V())), PromoteResult); (void)::fma(T(), U(), V()); + + ASSERT_SAME_TYPE(decltype(::hypot(T(), U(), V())), PromoteResult); + (void)::hypot(T(), U(), V()); } };