1*0fca6ea1SDimitry Andric // -*- C++ -*- 2*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 3*0fca6ea1SDimitry Andric // 4*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*0fca6ea1SDimitry Andric // 8*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 9*0fca6ea1SDimitry Andric 10*0fca6ea1SDimitry Andric #ifndef _LIBCPP___MATH_SPECIAL_FUNCTIONS_H 11*0fca6ea1SDimitry Andric #define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include <__config> 14*0fca6ea1SDimitry Andric #include <__math/copysign.h> 15*0fca6ea1SDimitry Andric #include <__math/traits.h> 16*0fca6ea1SDimitry Andric #include <__type_traits/enable_if.h> 17*0fca6ea1SDimitry Andric #include <__type_traits/is_integral.h> 18*0fca6ea1SDimitry Andric #include <limits> 19*0fca6ea1SDimitry Andric 20*0fca6ea1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 21*0fca6ea1SDimitry Andric # pragma GCC system_header 22*0fca6ea1SDimitry Andric #endif 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric #if _LIBCPP_STD_VER >= 17 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric template <class _Real> 29*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { 30*0fca6ea1SDimitry Andric // The Hermite polynomial H_n(x). 31*0fca6ea1SDimitry Andric // The implementation is based on the recurrence formula: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}. 32*0fca6ea1SDimitry Andric // Press, William H., et al. Numerical recipes 3rd edition: The art of scientific computing. 33*0fca6ea1SDimitry Andric // Cambridge university press, 2007, p. 183. 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric // NOLINTBEGIN(readability-identifier-naming) 36*0fca6ea1SDimitry Andric if (__math::isnan(__x)) 37*0fca6ea1SDimitry Andric return __x; 38*0fca6ea1SDimitry Andric 39*0fca6ea1SDimitry Andric _Real __H_0{1}; 40*0fca6ea1SDimitry Andric if (__n == 0) 41*0fca6ea1SDimitry Andric return __H_0; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric _Real __H_n_prev = __H_0; 44*0fca6ea1SDimitry Andric _Real __H_n = 2 * __x; 45*0fca6ea1SDimitry Andric for (unsigned __i = 1; __i < __n; ++__i) { 46*0fca6ea1SDimitry Andric _Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev); 47*0fca6ea1SDimitry Andric __H_n_prev = __H_n; 48*0fca6ea1SDimitry Andric __H_n = __H_n_next; 49*0fca6ea1SDimitry Andric } 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric if (!__math::isfinite(__H_n)) { 52*0fca6ea1SDimitry Andric // Overflow occured. Two possible cases: 53*0fca6ea1SDimitry Andric // n is odd: return infinity of the same sign as x. 54*0fca6ea1SDimitry Andric // n is even: return +Inf 55*0fca6ea1SDimitry Andric _Real __inf = std::numeric_limits<_Real>::infinity(); 56*0fca6ea1SDimitry Andric return (__n & 1) ? __math::copysign(__inf, __x) : __inf; 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric return __H_n; 59*0fca6ea1SDimitry Andric // NOLINTEND(readability-identifier-naming) 60*0fca6ea1SDimitry Andric } 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } 63*0fca6ea1SDimitry Andric 64*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { 65*0fca6ea1SDimitry Andric // use double internally -- float is too prone to overflow! 66*0fca6ea1SDimitry Andric return static_cast<float>(std::hermite(__n, static_cast<double>(__x))); 67*0fca6ea1SDimitry Andric } 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); } 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); } 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } 74*0fca6ea1SDimitry Andric 75*0fca6ea1SDimitry Andric template <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0> 76*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { 77*0fca6ea1SDimitry Andric return std::hermite(__n, static_cast<double>(__x)); 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric 80*0fca6ea1SDimitry Andric #endif // _LIBCPP_STD_VER >= 17 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric #endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H 85