Chris@102
|
1 ///////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
2 // Copyright 2013 John Maddock
|
Chris@102
|
3 // Distributed under the Boost
|
Chris@102
|
4 // Software License, Version 1.0. (See accompanying file
|
Chris@102
|
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
6
|
Chris@102
|
7 #ifndef BOOST_MATH_BERNOULLI_DETAIL_HPP
|
Chris@102
|
8 #define BOOST_MATH_BERNOULLI_DETAIL_HPP
|
Chris@102
|
9
|
Chris@102
|
10 #include <boost/config.hpp>
|
Chris@102
|
11 #include <boost/detail/lightweight_mutex.hpp>
|
Chris@102
|
12 #include <boost/utility/enable_if.hpp>
|
Chris@102
|
13 #include <boost/math/tools/toms748_solve.hpp>
|
Chris@102
|
14
|
Chris@102
|
15 #ifdef BOOST_HAS_THREADS
|
Chris@102
|
16
|
Chris@102
|
17 #ifndef BOOST_NO_CXX11_HDR_ATOMIC
|
Chris@102
|
18 # include <atomic>
|
Chris@102
|
19 # define BOOST_MATH_ATOMIC_NS std
|
Chris@102
|
20 #if ATOMIC_INT_LOCK_FREE == 2
|
Chris@102
|
21 typedef std::atomic<int> atomic_counter_type;
|
Chris@102
|
22 typedef int atomic_integer_type;
|
Chris@102
|
23 #elif ATOMIC_SHORT_LOCK_FREE == 2
|
Chris@102
|
24 typedef std::atomic<short> atomic_counter_type;
|
Chris@102
|
25 typedef short atomic_integer_type;
|
Chris@102
|
26 #elif ATOMIC_LONG_LOCK_FREE == 2
|
Chris@102
|
27 typedef std::atomic<long> atomic_counter_type;
|
Chris@102
|
28 typedef long atomic_integer_type;
|
Chris@102
|
29 #elif ATOMIC_LLONG_LOCK_FREE == 2
|
Chris@102
|
30 typedef std::atomic<long long> atomic_counter_type;
|
Chris@102
|
31 typedef long long atomic_integer_type;
|
Chris@102
|
32 #else
|
Chris@102
|
33 # define BOOST_MATH_NO_ATOMIC_INT
|
Chris@102
|
34 #endif
|
Chris@102
|
35
|
Chris@102
|
36 #else // BOOST_NO_CXX11_HDR_ATOMIC
|
Chris@102
|
37 //
|
Chris@102
|
38 // We need Boost.Atomic, but on any platform that supports auto-linking we do
|
Chris@102
|
39 // not need to link against a separate library:
|
Chris@102
|
40 //
|
Chris@102
|
41 #define BOOST_ATOMIC_NO_LIB
|
Chris@102
|
42 #include <boost/atomic.hpp>
|
Chris@102
|
43 # define BOOST_MATH_ATOMIC_NS boost
|
Chris@102
|
44
|
Chris@102
|
45 namespace boost{ namespace math{ namespace detail{
|
Chris@102
|
46
|
Chris@102
|
47 //
|
Chris@102
|
48 // We need a type to use as an atomic counter:
|
Chris@102
|
49 //
|
Chris@102
|
50 #if BOOST_ATOMIC_INT_LOCK_FREE == 2
|
Chris@102
|
51 typedef boost::atomic<int> atomic_counter_type;
|
Chris@102
|
52 typedef int atomic_integer_type;
|
Chris@102
|
53 #elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2
|
Chris@102
|
54 typedef boost::atomic<short> atomic_counter_type;
|
Chris@102
|
55 typedef short atomic_integer_type;
|
Chris@102
|
56 #elif BOOST_ATOMIC_LONG_LOCK_FREE == 2
|
Chris@102
|
57 typedef boost::atomic<long> atomic_counter_type;
|
Chris@102
|
58 typedef long atomic_integer_type;
|
Chris@102
|
59 #elif BOOST_ATOMIC_LLONG_LOCK_FREE == 2
|
Chris@102
|
60 typedef boost::atomic<long long> atomic_counter_type;
|
Chris@102
|
61 typedef long long atomic_integer_type;
|
Chris@102
|
62 #else
|
Chris@102
|
63 # define BOOST_MATH_NO_ATOMIC_INT
|
Chris@102
|
64 #endif
|
Chris@102
|
65
|
Chris@102
|
66 }}} // namespaces
|
Chris@102
|
67
|
Chris@102
|
68 #endif // BOOST_NO_CXX11_HDR_ATOMIC
|
Chris@102
|
69
|
Chris@102
|
70 #endif // BOOST_HAS_THREADS
|
Chris@102
|
71
|
Chris@102
|
72 namespace boost{ namespace math{ namespace detail{
|
Chris@102
|
73 //
|
Chris@102
|
74 // Asymptotic expansion for B2n due to
|
Chris@102
|
75 // Luschny LogB3 formula (http://www.luschny.de/math/primes/bernincl.html)
|
Chris@102
|
76 //
|
Chris@102
|
77 template <class T, class Policy>
|
Chris@102
|
78 T b2n_asymptotic(int n)
|
Chris@102
|
79 {
|
Chris@102
|
80 BOOST_MATH_STD_USING
|
Chris@102
|
81 const T nx = static_cast<T>(n);
|
Chris@102
|
82 const T nx2(nx * nx);
|
Chris@102
|
83
|
Chris@102
|
84 const T approximate_log_of_bernoulli_bn =
|
Chris@102
|
85 ((boost::math::constants::half<T>() + nx) * log(nx))
|
Chris@102
|
86 + ((boost::math::constants::half<T>() - nx) * log(boost::math::constants::pi<T>()))
|
Chris@102
|
87 + (((T(3) / 2) - nx) * boost::math::constants::ln_two<T>())
|
Chris@102
|
88 + ((nx * (T(2) - (nx2 * 7) * (1 + ((nx2 * 30) * ((nx2 * 12) - 1))))) / (((nx2 * nx2) * nx2) * 2520));
|
Chris@102
|
89 return ((n / 2) & 1 ? 1 : -1) * (approximate_log_of_bernoulli_bn > tools::log_max_value<T>()
|
Chris@102
|
90 ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, nx, Policy())
|
Chris@102
|
91 : static_cast<T>(exp(approximate_log_of_bernoulli_bn)));
|
Chris@102
|
92 }
|
Chris@102
|
93
|
Chris@102
|
94 template <class T, class Policy>
|
Chris@102
|
95 T t2n_asymptotic(int n)
|
Chris@102
|
96 {
|
Chris@102
|
97 BOOST_MATH_STD_USING
|
Chris@102
|
98 // Just get B2n and convert to a Tangent number:
|
Chris@102
|
99 T t2n = fabs(b2n_asymptotic<T, Policy>(2 * n)) / (2 * n);
|
Chris@102
|
100 T p2 = ldexp(T(1), n);
|
Chris@102
|
101 if(tools::max_value<T>() / p2 < t2n)
|
Chris@102
|
102 return policies::raise_overflow_error<T>("boost::math::tangent_t2n<%1%>(std::size_t)", 0, T(n), Policy());
|
Chris@102
|
103 t2n *= p2;
|
Chris@102
|
104 p2 -= 1;
|
Chris@102
|
105 if(tools::max_value<T>() / p2 < t2n)
|
Chris@102
|
106 return policies::raise_overflow_error<T>("boost::math::tangent_t2n<%1%>(std::size_t)", 0, Policy());
|
Chris@102
|
107 t2n *= p2;
|
Chris@102
|
108 return t2n;
|
Chris@102
|
109 }
|
Chris@102
|
110 //
|
Chris@102
|
111 // We need to know the approximate value of /n/ which will
|
Chris@102
|
112 // cause bernoulli_b2n<T>(n) to return infinity - this allows
|
Chris@102
|
113 // us to elude a great deal of runtime checking for values below
|
Chris@102
|
114 // n, and only perform the full overflow checks when we know that we're
|
Chris@102
|
115 // getting close to the point where our calculations will overflow.
|
Chris@102
|
116 // We use Luschny's LogB3 formula (http://www.luschny.de/math/primes/bernincl.html)
|
Chris@102
|
117 // to find the limit, and since we're dealing with the log of the Bernoulli numbers
|
Chris@102
|
118 // we need only perform the calculation at double precision and not with T
|
Chris@102
|
119 // (which may be a multiprecision type). The limit returned is within 1 of the true
|
Chris@102
|
120 // limit for all the types tested. Note that although the code below is basically
|
Chris@102
|
121 // the same as b2n_asymptotic above, it has been recast as a continuous real-valued
|
Chris@102
|
122 // function as this makes the root finding go smoother/faster. It also omits the
|
Chris@102
|
123 // sign of the Bernoulli number.
|
Chris@102
|
124 //
|
Chris@102
|
125 struct max_bernoulli_root_functor
|
Chris@102
|
126 {
|
Chris@102
|
127 max_bernoulli_root_functor(long long t) : target(static_cast<double>(t)) {}
|
Chris@102
|
128 double operator()(double n)
|
Chris@102
|
129 {
|
Chris@102
|
130 BOOST_MATH_STD_USING
|
Chris@102
|
131
|
Chris@102
|
132 // Luschny LogB3(n) formula.
|
Chris@102
|
133
|
Chris@102
|
134 const double nx2(n * n);
|
Chris@102
|
135
|
Chris@102
|
136 const double approximate_log_of_bernoulli_bn
|
Chris@102
|
137 = ((boost::math::constants::half<double>() + n) * log(n))
|
Chris@102
|
138 + ((boost::math::constants::half<double>() - n) * log(boost::math::constants::pi<double>()))
|
Chris@102
|
139 + (((double(3) / 2) - n) * boost::math::constants::ln_two<double>())
|
Chris@102
|
140 + ((n * (2 - (nx2 * 7) * (1 + ((nx2 * 30) * ((nx2 * 12) - 1))))) / (((nx2 * nx2) * nx2) * 2520));
|
Chris@102
|
141
|
Chris@102
|
142 return approximate_log_of_bernoulli_bn - target;
|
Chris@102
|
143 }
|
Chris@102
|
144 private:
|
Chris@102
|
145 double target;
|
Chris@102
|
146 };
|
Chris@102
|
147
|
Chris@102
|
148 template <class T, class Policy>
|
Chris@102
|
149 inline std::size_t find_bernoulli_overflow_limit(const mpl::false_&)
|
Chris@102
|
150 {
|
Chris@102
|
151 long long t = lltrunc(boost::math::tools::log_max_value<T>());
|
Chris@102
|
152 max_bernoulli_root_functor fun(t);
|
Chris@102
|
153 boost::math::tools::equal_floor tol;
|
Chris@102
|
154 boost::uintmax_t max_iter = boost::math::policies::get_max_root_iterations<Policy>();
|
Chris@102
|
155 return static_cast<std::size_t>(boost::math::tools::toms748_solve(fun, sqrt(double(t)), double(t), tol, max_iter).first) / 2;
|
Chris@102
|
156 }
|
Chris@102
|
157
|
Chris@102
|
158 template <class T, class Policy>
|
Chris@102
|
159 inline std::size_t find_bernoulli_overflow_limit(const mpl::true_&)
|
Chris@102
|
160 {
|
Chris@102
|
161 return max_bernoulli_index<bernoulli_imp_variant<T>::value>::value;
|
Chris@102
|
162 }
|
Chris@102
|
163
|
Chris@102
|
164 template <class T, class Policy>
|
Chris@102
|
165 std::size_t b2n_overflow_limit()
|
Chris@102
|
166 {
|
Chris@102
|
167 // This routine is called at program startup if it's called at all:
|
Chris@102
|
168 // that guarantees safe initialization of the static variable.
|
Chris@102
|
169 typedef mpl::bool_<(bernoulli_imp_variant<T>::value >= 1) && (bernoulli_imp_variant<T>::value <= 3)> tag_type;
|
Chris@102
|
170 static const std::size_t lim = find_bernoulli_overflow_limit<T, Policy>(tag_type());
|
Chris@102
|
171 return lim;
|
Chris@102
|
172 }
|
Chris@102
|
173
|
Chris@102
|
174 //
|
Chris@102
|
175 // The tangent numbers grow larger much more rapidly than the Bernoulli numbers do....
|
Chris@102
|
176 // so to compute the Bernoulli numbers from the tangent numbers, we need to avoid spurious
|
Chris@102
|
177 // overflow in the calculation, we can do this by scaling all the tangent number by some scale factor:
|
Chris@102
|
178 //
|
Chris@102
|
179 template <class T>
|
Chris@102
|
180 inline typename enable_if_c<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::radix == 2), T>::type tangent_scale_factor()
|
Chris@102
|
181 {
|
Chris@102
|
182 BOOST_MATH_STD_USING
|
Chris@102
|
183 return ldexp(T(1), std::numeric_limits<T>::min_exponent + 5);
|
Chris@102
|
184 }
|
Chris@102
|
185 template <class T>
|
Chris@102
|
186 inline typename disable_if_c<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::radix == 2), T>::type tangent_scale_factor()
|
Chris@102
|
187 {
|
Chris@102
|
188 return tools::min_value<T>() * 16;
|
Chris@102
|
189 }
|
Chris@102
|
190 //
|
Chris@102
|
191 // Initializer: ensure all our constants are initialized prior to the first call of main:
|
Chris@102
|
192 //
|
Chris@102
|
193 template <class T, class Policy>
|
Chris@102
|
194 struct bernoulli_initializer
|
Chris@102
|
195 {
|
Chris@102
|
196 struct init
|
Chris@102
|
197 {
|
Chris@102
|
198 init()
|
Chris@102
|
199 {
|
Chris@102
|
200 //
|
Chris@102
|
201 // We call twice, once to initialize our static table, and once to
|
Chris@102
|
202 // initialize our dymanic table:
|
Chris@102
|
203 //
|
Chris@102
|
204 boost::math::bernoulli_b2n<T>(2, Policy());
|
Chris@102
|
205 try{
|
Chris@102
|
206 boost::math::bernoulli_b2n<T>(max_bernoulli_b2n<T>::value + 1, Policy());
|
Chris@102
|
207 } catch(const std::overflow_error&){}
|
Chris@102
|
208 boost::math::tangent_t2n<T>(2, Policy());
|
Chris@102
|
209 }
|
Chris@102
|
210 void force_instantiate()const{}
|
Chris@102
|
211 };
|
Chris@102
|
212 static const init initializer;
|
Chris@102
|
213 static void force_instantiate()
|
Chris@102
|
214 {
|
Chris@102
|
215 initializer.force_instantiate();
|
Chris@102
|
216 }
|
Chris@102
|
217 };
|
Chris@102
|
218
|
Chris@102
|
219 template <class T, class Policy>
|
Chris@102
|
220 const typename bernoulli_initializer<T, Policy>::init bernoulli_initializer<T, Policy>::initializer;
|
Chris@102
|
221
|
Chris@102
|
222 //
|
Chris@102
|
223 // We need something to act as a cache for our calculated Bernoulli numbers. In order to
|
Chris@102
|
224 // ensure both fast access and thread safety, we need a stable table which may be extended
|
Chris@102
|
225 // in size, but which never reallocates: that way values already calculated may be accessed
|
Chris@102
|
226 // concurrently with another thread extending the table with new values.
|
Chris@102
|
227 //
|
Chris@102
|
228 // Very very simple vector class that will never allocate more than once, we could use
|
Chris@102
|
229 // boost::container::static_vector here, but that allocates on the stack, which may well
|
Chris@102
|
230 // cause issues for the amount of memory we want in the extreme case...
|
Chris@102
|
231 //
|
Chris@102
|
232 template <class T>
|
Chris@102
|
233 struct fixed_vector : private std::allocator<T>
|
Chris@102
|
234 {
|
Chris@102
|
235 typedef unsigned size_type;
|
Chris@102
|
236 typedef T* iterator;
|
Chris@102
|
237 typedef const T* const_iterator;
|
Chris@102
|
238 fixed_vector() : m_used(0)
|
Chris@102
|
239 {
|
Chris@102
|
240 std::size_t overflow_limit = 5 + b2n_overflow_limit<T, policies::policy<> >();
|
Chris@102
|
241 m_capacity = static_cast<unsigned>((std::min)(overflow_limit, static_cast<std::size_t>(100000u)));
|
Chris@102
|
242 m_data = this->allocate(m_capacity);
|
Chris@102
|
243 }
|
Chris@102
|
244 ~fixed_vector()
|
Chris@102
|
245 {
|
Chris@102
|
246 for(unsigned i = 0; i < m_used; ++i)
|
Chris@102
|
247 this->destroy(&m_data[i]);
|
Chris@102
|
248 this->deallocate(m_data, m_capacity);
|
Chris@102
|
249 }
|
Chris@102
|
250 T& operator[](unsigned n) { BOOST_ASSERT(n < m_used); return m_data[n]; }
|
Chris@102
|
251 const T& operator[](unsigned n)const { BOOST_ASSERT(n < m_used); return m_data[n]; }
|
Chris@102
|
252 unsigned size()const { return m_used; }
|
Chris@102
|
253 unsigned size() { return m_used; }
|
Chris@102
|
254 void resize(unsigned n, const T& val)
|
Chris@102
|
255 {
|
Chris@102
|
256 if(n > m_capacity)
|
Chris@102
|
257 throw std::runtime_error("Exhausted storage for Bernoulli numbers.");
|
Chris@102
|
258 for(unsigned i = m_used; i < n; ++i)
|
Chris@102
|
259 new (m_data + i) T(val);
|
Chris@102
|
260 m_used = n;
|
Chris@102
|
261 }
|
Chris@102
|
262 void resize(unsigned n) { resize(n, T()); }
|
Chris@102
|
263 T* begin() { return m_data; }
|
Chris@102
|
264 T* end() { return m_data + m_used; }
|
Chris@102
|
265 T* begin()const { return m_data; }
|
Chris@102
|
266 T* end()const { return m_data + m_used; }
|
Chris@102
|
267 unsigned capacity()const { return m_capacity; }
|
Chris@102
|
268 private:
|
Chris@102
|
269 T* m_data;
|
Chris@102
|
270 unsigned m_used, m_capacity;
|
Chris@102
|
271 };
|
Chris@102
|
272
|
Chris@102
|
273 template <class T, class Policy>
|
Chris@102
|
274 class bernoulli_numbers_cache
|
Chris@102
|
275 {
|
Chris@102
|
276 public:
|
Chris@102
|
277 bernoulli_numbers_cache() : m_overflow_limit((std::numeric_limits<std::size_t>::max)())
|
Chris@102
|
278 #if defined(BOOST_HAS_THREADS) && !defined(BOOST_MATH_NO_ATOMIC_INT)
|
Chris@102
|
279 , m_counter(0)
|
Chris@102
|
280 #endif
|
Chris@102
|
281 {}
|
Chris@102
|
282
|
Chris@102
|
283 typedef fixed_vector<T> container_type;
|
Chris@102
|
284
|
Chris@102
|
285 void tangent(std::size_t m)
|
Chris@102
|
286 {
|
Chris@102
|
287 static const std::size_t min_overflow_index = b2n_overflow_limit<T, Policy>() - 1;
|
Chris@102
|
288 tn.resize(static_cast<typename container_type::size_type>(m), T(0U));
|
Chris@102
|
289
|
Chris@102
|
290 BOOST_MATH_INSTRUMENT_VARIABLE(min_overflow_index);
|
Chris@102
|
291
|
Chris@102
|
292 std::size_t prev_size = m_intermediates.size();
|
Chris@102
|
293 m_intermediates.resize(m, T(0U));
|
Chris@102
|
294
|
Chris@102
|
295 if(prev_size == 0)
|
Chris@102
|
296 {
|
Chris@102
|
297 m_intermediates[1] = tangent_scale_factor<T>() /*T(1U)*/;
|
Chris@102
|
298 tn[0U] = T(0U);
|
Chris@102
|
299 tn[1U] = tangent_scale_factor<T>()/* T(1U)*/;
|
Chris@102
|
300 BOOST_MATH_INSTRUMENT_VARIABLE(tn[0]);
|
Chris@102
|
301 BOOST_MATH_INSTRUMENT_VARIABLE(tn[1]);
|
Chris@102
|
302 }
|
Chris@102
|
303
|
Chris@102
|
304 for(std::size_t i = std::max<size_t>(2, prev_size); i < m; i++)
|
Chris@102
|
305 {
|
Chris@102
|
306 bool overflow_check = false;
|
Chris@102
|
307 if(i >= min_overflow_index && (boost::math::tools::max_value<T>() / (i-1) < m_intermediates[1]) )
|
Chris@102
|
308 {
|
Chris@102
|
309 std::fill(tn.begin() + i, tn.end(), boost::math::tools::max_value<T>());
|
Chris@102
|
310 break;
|
Chris@102
|
311 }
|
Chris@102
|
312 m_intermediates[1] = m_intermediates[1] * (i-1);
|
Chris@102
|
313 for(std::size_t j = 2; j <= i; j++)
|
Chris@102
|
314 {
|
Chris@102
|
315 overflow_check =
|
Chris@102
|
316 (i >= min_overflow_index) && (
|
Chris@102
|
317 (boost::math::tools::max_value<T>() / (i - j) < m_intermediates[j])
|
Chris@102
|
318 || (boost::math::tools::max_value<T>() / (i - j + 2) < m_intermediates[j-1])
|
Chris@102
|
319 || (boost::math::tools::max_value<T>() - m_intermediates[j] * (i - j) < m_intermediates[j-1] * (i - j + 2))
|
Chris@102
|
320 || ((boost::math::isinf)(m_intermediates[j]))
|
Chris@102
|
321 );
|
Chris@102
|
322
|
Chris@102
|
323 if(overflow_check)
|
Chris@102
|
324 {
|
Chris@102
|
325 std::fill(tn.begin() + i, tn.end(), boost::math::tools::max_value<T>());
|
Chris@102
|
326 break;
|
Chris@102
|
327 }
|
Chris@102
|
328 m_intermediates[j] = m_intermediates[j] * (i - j) + m_intermediates[j-1] * (i - j + 2);
|
Chris@102
|
329 }
|
Chris@102
|
330 if(overflow_check)
|
Chris@102
|
331 break; // already filled the tn...
|
Chris@102
|
332 tn[static_cast<typename container_type::size_type>(i)] = m_intermediates[i];
|
Chris@102
|
333 BOOST_MATH_INSTRUMENT_VARIABLE(i);
|
Chris@102
|
334 BOOST_MATH_INSTRUMENT_VARIABLE(tn[static_cast<typename container_type::size_type>(i)]);
|
Chris@102
|
335 }
|
Chris@102
|
336 }
|
Chris@102
|
337
|
Chris@102
|
338 void tangent_numbers_series(const std::size_t m)
|
Chris@102
|
339 {
|
Chris@102
|
340 BOOST_MATH_STD_USING
|
Chris@102
|
341 static const std::size_t min_overflow_index = b2n_overflow_limit<T, Policy>() - 1;
|
Chris@102
|
342
|
Chris@102
|
343 typename container_type::size_type old_size = bn.size();
|
Chris@102
|
344
|
Chris@102
|
345 tangent(m);
|
Chris@102
|
346 bn.resize(static_cast<typename container_type::size_type>(m));
|
Chris@102
|
347
|
Chris@102
|
348 if(!old_size)
|
Chris@102
|
349 {
|
Chris@102
|
350 bn[0] = 1;
|
Chris@102
|
351 old_size = 1;
|
Chris@102
|
352 }
|
Chris@102
|
353
|
Chris@102
|
354 T power_two(ldexp(T(1), static_cast<int>(2 * old_size)));
|
Chris@102
|
355
|
Chris@102
|
356 for(std::size_t i = old_size; i < m; i++)
|
Chris@102
|
357 {
|
Chris@102
|
358 T b(static_cast<T>(i * 2));
|
Chris@102
|
359 //
|
Chris@102
|
360 // Not only do we need to take care to avoid spurious over/under flow in
|
Chris@102
|
361 // the calculation, but we also need to avoid overflow altogether in case
|
Chris@102
|
362 // we're calculating with a type where "bad things" happen in that case:
|
Chris@102
|
363 //
|
Chris@102
|
364 b = b / (power_two * tangent_scale_factor<T>());
|
Chris@102
|
365 b /= (power_two - 1);
|
Chris@102
|
366 bool overflow_check = (i >= min_overflow_index) && (tools::max_value<T>() / tn[static_cast<typename container_type::size_type>(i)] < b);
|
Chris@102
|
367 if(overflow_check)
|
Chris@102
|
368 {
|
Chris@102
|
369 m_overflow_limit = i;
|
Chris@102
|
370 while(i < m)
|
Chris@102
|
371 {
|
Chris@102
|
372 b = std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : tools::max_value<T>();
|
Chris@102
|
373 bn[static_cast<typename container_type::size_type>(i)] = ((i % 2U) ? b : T(-b));
|
Chris@102
|
374 ++i;
|
Chris@102
|
375 }
|
Chris@102
|
376 break;
|
Chris@102
|
377 }
|
Chris@102
|
378 else
|
Chris@102
|
379 {
|
Chris@102
|
380 b *= tn[static_cast<typename container_type::size_type>(i)];
|
Chris@102
|
381 }
|
Chris@102
|
382
|
Chris@102
|
383 power_two = ldexp(power_two, 2);
|
Chris@102
|
384
|
Chris@102
|
385 const bool b_neg = i % 2 == 0;
|
Chris@102
|
386
|
Chris@102
|
387 bn[static_cast<typename container_type::size_type>(i)] = ((!b_neg) ? b : T(-b));
|
Chris@102
|
388 }
|
Chris@102
|
389 }
|
Chris@102
|
390
|
Chris@102
|
391 template <class OutputIterator>
|
Chris@102
|
392 OutputIterator copy_bernoulli_numbers(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol)
|
Chris@102
|
393 {
|
Chris@102
|
394 //
|
Chris@102
|
395 // There are basically 3 thread safety options:
|
Chris@102
|
396 //
|
Chris@102
|
397 // 1) There are no threads (BOOST_HAS_THREADS is not defined).
|
Chris@102
|
398 // 2) There are threads, but we do not have a true atomic integer type,
|
Chris@102
|
399 // in this case we just use a mutex to guard against race conditions.
|
Chris@102
|
400 // 3) There are threads, and we have an atomic integer: in this case we can
|
Chris@102
|
401 // use the double-checked locking pattern to avoid thread synchronisation
|
Chris@102
|
402 // when accessing values already in the cache.
|
Chris@102
|
403 //
|
Chris@102
|
404 // First off handle the common case for overflow and/or asymptotic expansion:
|
Chris@102
|
405 //
|
Chris@102
|
406 if(start + n > bn.capacity())
|
Chris@102
|
407 {
|
Chris@102
|
408 if(start < bn.capacity())
|
Chris@102
|
409 {
|
Chris@102
|
410 out = copy_bernoulli_numbers(out, start, bn.capacity() - start, pol);
|
Chris@102
|
411 n -= bn.capacity() - start;
|
Chris@102
|
412 start = static_cast<std::size_t>(bn.capacity());
|
Chris@102
|
413 }
|
Chris@102
|
414 if(start < b2n_overflow_limit<T, Policy>() + 2u)
|
Chris@102
|
415 {
|
Chris@102
|
416 for(; n; ++start, --n)
|
Chris@102
|
417 {
|
Chris@102
|
418 *out = b2n_asymptotic<T, Policy>(static_cast<typename container_type::size_type>(start * 2U));
|
Chris@102
|
419 ++out;
|
Chris@102
|
420 }
|
Chris@102
|
421 }
|
Chris@102
|
422 for(; n; ++start, --n)
|
Chris@102
|
423 {
|
Chris@102
|
424 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(start), pol);
|
Chris@102
|
425 ++out;
|
Chris@102
|
426 }
|
Chris@102
|
427 return out;
|
Chris@102
|
428 }
|
Chris@102
|
429 #if !defined(BOOST_HAS_THREADS)
|
Chris@102
|
430 //
|
Chris@102
|
431 // Single threaded code, very simple:
|
Chris@102
|
432 //
|
Chris@102
|
433 if(start + n >= bn.size())
|
Chris@102
|
434 {
|
Chris@102
|
435 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
436 tangent_numbers_series(new_size);
|
Chris@102
|
437 }
|
Chris@102
|
438
|
Chris@102
|
439 for(std::size_t i = (std::max)(max_bernoulli_b2n<T>::value + 1, start); i < start + n; ++i)
|
Chris@102
|
440 {
|
Chris@102
|
441 *out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[i];
|
Chris@102
|
442 ++out;
|
Chris@102
|
443 }
|
Chris@102
|
444 #elif defined(BOOST_MATH_NO_ATOMIC_INT)
|
Chris@102
|
445 //
|
Chris@102
|
446 // We need to grab a mutex every time we get here, for both readers and writers:
|
Chris@102
|
447 //
|
Chris@102
|
448 boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
|
Chris@102
|
449 if(start + n >= bn.size())
|
Chris@102
|
450 {
|
Chris@102
|
451 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
452 tangent_numbers_series(new_size);
|
Chris@102
|
453 }
|
Chris@102
|
454
|
Chris@102
|
455 for(std::size_t i = (std::max)(max_bernoulli_b2n<T>::value + 1, start); i < start + n; ++i)
|
Chris@102
|
456 {
|
Chris@102
|
457 *out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[i];
|
Chris@102
|
458 ++out;
|
Chris@102
|
459 }
|
Chris@102
|
460
|
Chris@102
|
461 #else
|
Chris@102
|
462 //
|
Chris@102
|
463 // Double-checked locking pattern, lets us access cached already cached values
|
Chris@102
|
464 // without locking:
|
Chris@102
|
465 //
|
Chris@102
|
466 // Get the counter and see if we need to calculate more constants:
|
Chris@102
|
467 //
|
Chris@102
|
468 if(static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|
Chris@102
|
469 {
|
Chris@102
|
470 boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
|
Chris@102
|
471
|
Chris@102
|
472 if(static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|
Chris@102
|
473 {
|
Chris@102
|
474 if(start + n >= bn.size())
|
Chris@102
|
475 {
|
Chris@102
|
476 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
477 tangent_numbers_series(new_size);
|
Chris@102
|
478 }
|
Chris@102
|
479 m_counter.store(static_cast<atomic_integer_type>(bn.size()), BOOST_MATH_ATOMIC_NS::memory_order_release);
|
Chris@102
|
480 }
|
Chris@102
|
481 }
|
Chris@102
|
482
|
Chris@102
|
483 for(std::size_t i = (std::max)(static_cast<std::size_t>(max_bernoulli_b2n<T>::value + 1), start); i < start + n; ++i)
|
Chris@102
|
484 {
|
Chris@102
|
485 *out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[static_cast<typename container_type::size_type>(i)];
|
Chris@102
|
486 ++out;
|
Chris@102
|
487 }
|
Chris@102
|
488
|
Chris@102
|
489 #endif
|
Chris@102
|
490 return out;
|
Chris@102
|
491 }
|
Chris@102
|
492
|
Chris@102
|
493 template <class OutputIterator>
|
Chris@102
|
494 OutputIterator copy_tangent_numbers(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol)
|
Chris@102
|
495 {
|
Chris@102
|
496 //
|
Chris@102
|
497 // There are basically 3 thread safety options:
|
Chris@102
|
498 //
|
Chris@102
|
499 // 1) There are no threads (BOOST_HAS_THREADS is not defined).
|
Chris@102
|
500 // 2) There are threads, but we do not have a true atomic integer type,
|
Chris@102
|
501 // in this case we just use a mutex to guard against race conditions.
|
Chris@102
|
502 // 3) There are threads, and we have an atomic integer: in this case we can
|
Chris@102
|
503 // use the double-checked locking pattern to avoid thread synchronisation
|
Chris@102
|
504 // when accessing values already in the cache.
|
Chris@102
|
505 //
|
Chris@102
|
506 //
|
Chris@102
|
507 // First off handle the common case for overflow and/or asymptotic expansion:
|
Chris@102
|
508 //
|
Chris@102
|
509 if(start + n > bn.capacity())
|
Chris@102
|
510 {
|
Chris@102
|
511 if(start < bn.capacity())
|
Chris@102
|
512 {
|
Chris@102
|
513 out = copy_tangent_numbers(out, start, bn.capacity() - start, pol);
|
Chris@102
|
514 n -= bn.capacity() - start;
|
Chris@102
|
515 start = static_cast<std::size_t>(bn.capacity());
|
Chris@102
|
516 }
|
Chris@102
|
517 if(start < b2n_overflow_limit<T, Policy>() + 2u)
|
Chris@102
|
518 {
|
Chris@102
|
519 for(; n; ++start, --n)
|
Chris@102
|
520 {
|
Chris@102
|
521 *out = t2n_asymptotic<T, Policy>(static_cast<typename container_type::size_type>(start));
|
Chris@102
|
522 ++out;
|
Chris@102
|
523 }
|
Chris@102
|
524 }
|
Chris@102
|
525 for(; n; ++start, --n)
|
Chris@102
|
526 {
|
Chris@102
|
527 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(start), pol);
|
Chris@102
|
528 ++out;
|
Chris@102
|
529 }
|
Chris@102
|
530 return out;
|
Chris@102
|
531 }
|
Chris@102
|
532 #if !defined(BOOST_HAS_THREADS)
|
Chris@102
|
533 //
|
Chris@102
|
534 // Single threaded code, very simple:
|
Chris@102
|
535 //
|
Chris@102
|
536 if(start + n >= bn.size())
|
Chris@102
|
537 {
|
Chris@102
|
538 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
539 tangent_numbers_series(new_size);
|
Chris@102
|
540 }
|
Chris@102
|
541
|
Chris@102
|
542 for(std::size_t i = start; i < start + n; ++i)
|
Chris@102
|
543 {
|
Chris@102
|
544 if(i >= m_overflow_limit)
|
Chris@102
|
545 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
546 else
|
Chris@102
|
547 {
|
Chris@102
|
548 if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
|
Chris@102
|
549 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
550 else
|
Chris@102
|
551 *out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
|
Chris@102
|
552 }
|
Chris@102
|
553 ++out;
|
Chris@102
|
554 }
|
Chris@102
|
555 #elif defined(BOOST_MATH_NO_ATOMIC_INT)
|
Chris@102
|
556 //
|
Chris@102
|
557 // We need to grab a mutex every time we get here, for both readers and writers:
|
Chris@102
|
558 //
|
Chris@102
|
559 boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
|
Chris@102
|
560 if(start + n >= bn.size())
|
Chris@102
|
561 {
|
Chris@102
|
562 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
563 tangent_numbers_series(new_size);
|
Chris@102
|
564 }
|
Chris@102
|
565
|
Chris@102
|
566 for(std::size_t i = start; i < start + n; ++i)
|
Chris@102
|
567 {
|
Chris@102
|
568 if(i >= m_overflow_limit)
|
Chris@102
|
569 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
570 else
|
Chris@102
|
571 {
|
Chris@102
|
572 if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
|
Chris@102
|
573 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
574 else
|
Chris@102
|
575 *out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
|
Chris@102
|
576 }
|
Chris@102
|
577 ++out;
|
Chris@102
|
578 }
|
Chris@102
|
579
|
Chris@102
|
580 #else
|
Chris@102
|
581 //
|
Chris@102
|
582 // Double-checked locking pattern, lets us access cached already cached values
|
Chris@102
|
583 // without locking:
|
Chris@102
|
584 //
|
Chris@102
|
585 // Get the counter and see if we need to calculate more constants:
|
Chris@102
|
586 //
|
Chris@102
|
587 if(static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|
Chris@102
|
588 {
|
Chris@102
|
589 boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
|
Chris@102
|
590
|
Chris@102
|
591 if(static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|
Chris@102
|
592 {
|
Chris@102
|
593 if(start + n >= bn.size())
|
Chris@102
|
594 {
|
Chris@102
|
595 std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
|
Chris@102
|
596 tangent_numbers_series(new_size);
|
Chris@102
|
597 }
|
Chris@102
|
598 m_counter.store(static_cast<atomic_integer_type>(bn.size()), BOOST_MATH_ATOMIC_NS::memory_order_release);
|
Chris@102
|
599 }
|
Chris@102
|
600 }
|
Chris@102
|
601
|
Chris@102
|
602 for(std::size_t i = start; i < start + n; ++i)
|
Chris@102
|
603 {
|
Chris@102
|
604 if(i >= m_overflow_limit)
|
Chris@102
|
605 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
606 else
|
Chris@102
|
607 {
|
Chris@102
|
608 if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
|
Chris@102
|
609 *out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
|
Chris@102
|
610 else
|
Chris@102
|
611 *out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
|
Chris@102
|
612 }
|
Chris@102
|
613 ++out;
|
Chris@102
|
614 }
|
Chris@102
|
615
|
Chris@102
|
616 #endif
|
Chris@102
|
617 return out;
|
Chris@102
|
618 }
|
Chris@102
|
619
|
Chris@102
|
620 private:
|
Chris@102
|
621 //
|
Chris@102
|
622 // The caches for Bernoulli and tangent numbers, once allocated,
|
Chris@102
|
623 // these must NEVER EVER reallocate as it breaks our thread
|
Chris@102
|
624 // safety guarentees:
|
Chris@102
|
625 //
|
Chris@102
|
626 fixed_vector<T> bn, tn;
|
Chris@102
|
627 std::vector<T> m_intermediates;
|
Chris@102
|
628 // The value at which we know overflow has already occured for the Bn:
|
Chris@102
|
629 std::size_t m_overflow_limit;
|
Chris@102
|
630 #if !defined(BOOST_HAS_THREADS)
|
Chris@102
|
631 #elif defined(BOOST_MATH_NO_ATOMIC_INT)
|
Chris@102
|
632 boost::detail::lightweight_mutex m_mutex;
|
Chris@102
|
633 #else
|
Chris@102
|
634 boost::detail::lightweight_mutex m_mutex;
|
Chris@102
|
635 atomic_counter_type m_counter;
|
Chris@102
|
636 #endif
|
Chris@102
|
637 };
|
Chris@102
|
638
|
Chris@102
|
639 template <class T, class Policy>
|
Chris@102
|
640 inline bernoulli_numbers_cache<T, Policy>& get_bernoulli_numbers_cache()
|
Chris@102
|
641 {
|
Chris@102
|
642 //
|
Chris@102
|
643 // Force this function to be called at program startup so all the static variables
|
Chris@102
|
644 // get initailzed then (thread safety).
|
Chris@102
|
645 //
|
Chris@102
|
646 bernoulli_initializer<T, Policy>::force_instantiate();
|
Chris@102
|
647 static bernoulli_numbers_cache<T, Policy> data;
|
Chris@102
|
648 return data;
|
Chris@102
|
649 }
|
Chris@102
|
650
|
Chris@102
|
651 }}}
|
Chris@102
|
652
|
Chris@102
|
653 #endif // BOOST_MATH_BERNOULLI_DETAIL_HPP
|