bernoulli_details.hpp 25 KB

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