aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/bits/sf_bernoulli.tcc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/bits/sf_bernoulli.tcc')
-rw-r--r--libstdc++-v3/include/bits/sf_bernoulli.tcc191
1 files changed, 191 insertions, 0 deletions
diff --git a/libstdc++-v3/include/bits/sf_bernoulli.tcc b/libstdc++-v3/include/bits/sf_bernoulli.tcc
new file mode 100644
index 00000000000..43e8737cb41
--- /dev/null
+++ b/libstdc++-v3/include/bits/sf_bernoulli.tcc
@@ -0,0 +1,191 @@
+// Special functions -*- C++ -*-
+
+// Copyright (C) 2017 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.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/sf_bernoulli.tcc
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{cmath}
+ */
+
+//
+// C++ Mathematical Special Functions
+//
+
+#ifndef _GLIBCXX_BITS_SF_BERNOULLI_TCC
+#define _GLIBCXX_BITS_SF_BERNOULLI_TCC 1
+
+#pragma GCC system_header
+
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+// Implementation-space details.
+namespace __detail
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /**
+ * @brief This returns Bernoulli numbers from a table or by summation
+ * for larger values.
+ * @f[
+ * B_{2n} = (-1)^{n+1} 2\frac{(2n)!}{(2\pi)^{2n}} \zeta(2n)
+ * @f]
+ *
+ * Note that
+ * @f[
+ * \zeta(2n) - 1 = (-1)^{n+1} \frac{(2\pi)^{2n}}{(2n)!} B_{2n} - 2
+ * @f]
+ * are small and rapidly decreasing finctions of n.
+ *
+ * @param __n the order n of the Bernoulli number.
+ * @return The Bernoulli number of order n.
+ */
+ template<typename _Tp>
+ _GLIBCXX14_CONSTEXPR _Tp
+ __bernoulli_series(unsigned int __n)
+ {
+ constexpr unsigned long _S_num_bern_tab = 12;
+ constexpr _Tp
+ _S_bernoulli_2n[_S_num_bern_tab]
+ {
+ _Tp{1ULL},
+ _Tp{1ULL} / _Tp{6ULL},
+ -_Tp{1ULL} / _Tp{30ULL},
+ _Tp{1ULL} / _Tp{42ULL},
+ -_Tp{1ULL} / _Tp{30ULL},
+ _Tp{5ULL} / _Tp{66ULL},
+ -_Tp{691ULL} / _Tp{2730ULL},
+ _Tp{7ULL} / _Tp{6ULL},
+ -_Tp{3617ULL} / _Tp{510ULL},
+ _Tp{43867ULL} / _Tp{798ULL},
+ -_Tp{174611ULL} / _Tp{330ULL},
+ _Tp{854513ULL} / _Tp{138ULL}
+ };
+
+ if (__n == 0)
+ return _Tp{1};
+ else if (__n == 1)
+ return -_Tp{1} / _Tp{2};
+ // Take care of the rest of the odd ones.
+ else if (__n % 2 == 1)
+ return _Tp{0};
+ // Take care of some small evens that are painful for the series.
+ else if (__n / 2 < _S_num_bern_tab)
+ return _S_bernoulli_2n[__n / 2];
+ else
+ {
+ constexpr auto _S_eps = __gnu_cxx::__epsilon<>(_Tp{});
+ constexpr auto _S_2pi = __gnu_cxx::__const_2_pi(_Tp{});
+ auto __fact = _Tp{1};
+ if ((__n / 2) % 2 == 0)
+ __fact *= -_Tp{1};
+ for (unsigned int __k = 1; __k <= __n; ++__k)
+ __fact *= __k / _S_2pi;
+ __fact *= _Tp{2};
+
+ // Riemann zeta function minus-1 for even integer argument.
+ auto __sum = _Tp{0};
+ for (unsigned int __i = 2; __i < 1000; ++__i)
+ {
+ auto __term = std::pow(_Tp(__i), -_Tp(__n));
+ __sum += __term;
+ if (__term < __gnu_cxx::__epsilon<_Tp>() * __sum)
+ break;
+ }
+
+ return __fact + __fact * __sum;
+ }
+ }
+
+ /**
+ * @brief This returns Bernoulli number @f$ B_n @f$.
+ *
+ * @param __n the order n of the Bernoulli number.
+ * @return The Bernoulli number of order n.
+ */
+ template<typename _Tp>
+ _GLIBCXX14_CONSTEXPR _Tp
+ __bernoulli(unsigned int __n)
+ { return __bernoulli_series<_Tp>(__n); }
+
+ /**
+ * @brief This returns Bernoulli number @f$ B_2n @f$ at even integer
+ * arguments @f$ 2n @f$.
+ *
+ * @param __n the half-order n of the Bernoulli number.
+ * @return The Bernoulli number of order 2n.
+ */
+ template<typename _Tp>
+ _GLIBCXX14_CONSTEXPR _Tp
+ __bernoulli_2n(unsigned int __n)
+ { return __bernoulli_series<_Tp>(2 * __n); }
+
+ /**
+ * Return the Bernoulli polynomial @f$ B_n(x) @f$ of order n at argument x.
+ *
+ * The values at 0 and 1 are equal to the corresponding Bernoulli number:
+ * @f[
+ * B_n(0) = B_n(1) = B_n
+ * @f]
+ *
+ * The derivative is proportional to the previous polynomial:
+ * @f[
+ * B_n'(x) = n * B_{n-1}(x)
+ * @f]
+ *
+ * The series expansion is:
+ * @f[
+ * B_n(x) = \sum_{k=0}^{n} B_k binom{n}{k} x^{n-k}
+ * @f]
+ *
+ * A useful argument promotion is:
+ * @f[
+ * B_n(x+1) - B_n(x) = n * x^{n-1}
+ * @f]
+ */
+ template<typename _Tp>
+ _Tp
+ __bernoulli(unsigned int __n, _Tp __x)
+ {
+ if (__isnan(__x))
+ return std::numeric_limits<_Tp>::quiet_NaN();
+ else
+ {
+ auto _B_n = std::__detail::__bernoulli<_Tp>(0);
+ auto __binomial = _Tp{1};
+ for (auto __k = 1u; __k <= __n; ++__k)
+ {
+ __binomial *= _Tp(__n + 1 - __k) / _Tp(__k);
+ _B_n = __x * _B_n + __binomial
+ * std::__detail::__bernoulli<_Tp>(__k);
+ }
+ return _B_n;
+ }
+ }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace __detail
+} // namespace std
+
+#endif // _GLIBCXX_BITS_SF_BERNOULLI_TCC
+