bernoulli_details.hpp 26 KB

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