PageRenderTime 54ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/山火-ヤギの咆哮-/lib/boost_1_45_0/boost/math/distributions/detail/inv_discrete_quantile.hpp

https://gitlab.com/kokeiro001/YamabiYagiNoHoko
C++ Header | 481 lines | 371 code | 26 blank | 84 comment | 52 complexity | 035ed587a048e4a0517a6a2f69bbe869 MD5 | raw file
  1. // Copyright John Maddock 2007.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
  6. #define BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
  7. #include <algorithm>
  8. namespace boost{ namespace math{ namespace detail{
  9. //
  10. // Functor for root finding algorithm:
  11. //
  12. template <class Dist>
  13. struct distribution_quantile_finder
  14. {
  15. typedef typename Dist::value_type value_type;
  16. typedef typename Dist::policy_type policy_type;
  17. distribution_quantile_finder(const Dist d, value_type p, value_type q)
  18. : dist(d), target(p < q ? p : q), comp(p < q ? false : true) {}
  19. value_type operator()(value_type const& x)
  20. {
  21. return comp ? target - cdf(complement(dist, x)) : cdf(dist, x) - target;
  22. }
  23. private:
  24. Dist dist;
  25. value_type target;
  26. bool comp;
  27. };
  28. //
  29. // The purpose of adjust_bounds, is to toggle the last bit of the
  30. // range so that both ends round to the same integer, if possible.
  31. // If they do both round the same then we terminate the search
  32. // for the root *very* quickly when finding an integer result.
  33. // At the point that this function is called we know that "a" is
  34. // below the root and "b" above it, so this change can not result
  35. // in the root no longer being bracketed.
  36. //
  37. template <class Real, class Tol>
  38. void adjust_bounds(Real& /* a */, Real& /* b */, Tol const& /* tol */){}
  39. template <class Real>
  40. void adjust_bounds(Real& /* a */, Real& b, tools::equal_floor const& /* tol */)
  41. {
  42. BOOST_MATH_STD_USING
  43. b -= tools::epsilon<Real>() * b;
  44. }
  45. template <class Real>
  46. void adjust_bounds(Real& a, Real& /* b */, tools::equal_ceil const& /* tol */)
  47. {
  48. BOOST_MATH_STD_USING
  49. a += tools::epsilon<Real>() * a;
  50. }
  51. template <class Real>
  52. void adjust_bounds(Real& a, Real& b, tools::equal_nearest_integer const& /* tol */)
  53. {
  54. BOOST_MATH_STD_USING
  55. a += tools::epsilon<Real>() * a;
  56. b -= tools::epsilon<Real>() * b;
  57. }
  58. //
  59. // This is where all the work is done:
  60. //
  61. template <class Dist, class Tolerance>
  62. typename Dist::value_type
  63. do_inverse_discrete_quantile(
  64. const Dist& dist,
  65. const typename Dist::value_type& p,
  66. const typename Dist::value_type& q,
  67. typename Dist::value_type guess,
  68. const typename Dist::value_type& multiplier,
  69. typename Dist::value_type adder,
  70. const Tolerance& tol,
  71. boost::uintmax_t& max_iter)
  72. {
  73. typedef typename Dist::value_type value_type;
  74. typedef typename Dist::policy_type policy_type;
  75. static const char* function = "boost::math::do_inverse_discrete_quantile<%1%>";
  76. BOOST_MATH_STD_USING
  77. distribution_quantile_finder<Dist> f(dist, p, q);
  78. //
  79. // Max bounds of the distribution:
  80. //
  81. value_type min_bound, max_bound;
  82. boost::math::tie(min_bound, max_bound) = support(dist);
  83. if(guess > max_bound)
  84. guess = max_bound;
  85. if(guess < min_bound)
  86. guess = min_bound;
  87. value_type fa = f(guess);
  88. boost::uintmax_t count = max_iter - 1;
  89. value_type fb(fa), a(guess), b =0; // Compiler warning C4701: potentially uninitialized local variable 'b' used
  90. if(fa == 0)
  91. return guess;
  92. //
  93. // For small expected results, just use a linear search:
  94. //
  95. if(guess < 10)
  96. {
  97. b = a;
  98. while((a < 10) && (fa * fb >= 0))
  99. {
  100. if(fb <= 0)
  101. {
  102. a = b;
  103. b = a + 1;
  104. if(b > max_bound)
  105. b = max_bound;
  106. fb = f(b);
  107. --count;
  108. if(fb == 0)
  109. return b;
  110. }
  111. else
  112. {
  113. b = a;
  114. a = (std::max)(value_type(b - 1), value_type(0));
  115. if(a < min_bound)
  116. a = min_bound;
  117. fa = f(a);
  118. --count;
  119. if(fa == 0)
  120. return a;
  121. }
  122. }
  123. }
  124. //
  125. // Try and bracket using a couple of additions first,
  126. // we're assuming that "guess" is likely to be accurate
  127. // to the nearest int or so:
  128. //
  129. else if(adder != 0)
  130. {
  131. //
  132. // If we're looking for a large result, then bump "adder" up
  133. // by a bit to increase our chances of bracketing the root:
  134. //
  135. //adder = (std::max)(adder, 0.001f * guess);
  136. if(fa < 0)
  137. {
  138. b = a + adder;
  139. if(b > max_bound)
  140. b = max_bound;
  141. }
  142. else
  143. {
  144. b = (std::max)(value_type(a - adder), value_type(0));
  145. if(b < min_bound)
  146. b = min_bound;
  147. }
  148. fb = f(b);
  149. --count;
  150. if(fb == 0)
  151. return b;
  152. if(count && (fa * fb >= 0))
  153. {
  154. //
  155. // We didn't bracket the root, try
  156. // once more:
  157. //
  158. a = b;
  159. fa = fb;
  160. if(fa < 0)
  161. {
  162. b = a + adder;
  163. if(b > max_bound)
  164. b = max_bound;
  165. }
  166. else
  167. {
  168. b = (std::max)(value_type(a - adder), value_type(0));
  169. if(b < min_bound)
  170. b = min_bound;
  171. }
  172. fb = f(b);
  173. --count;
  174. }
  175. if(a > b)
  176. {
  177. using std::swap;
  178. swap(a, b);
  179. swap(fa, fb);
  180. }
  181. }
  182. //
  183. // If the root hasn't been bracketed yet, try again
  184. // using the multiplier this time:
  185. //
  186. if((boost::math::sign)(fb) == (boost::math::sign)(fa))
  187. {
  188. if(fa < 0)
  189. {
  190. //
  191. // Zero is to the right of x2, so walk upwards
  192. // until we find it:
  193. //
  194. while((boost::math::sign)(fb) == (boost::math::sign)(fa))
  195. {
  196. if(count == 0)
  197. policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, policy_type());
  198. a = b;
  199. fa = fb;
  200. b *= multiplier;
  201. if(b > max_bound)
  202. b = max_bound;
  203. fb = f(b);
  204. --count;
  205. BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
  206. }
  207. }
  208. else
  209. {
  210. //
  211. // Zero is to the left of a, so walk downwards
  212. // until we find it:
  213. //
  214. while((boost::math::sign)(fb) == (boost::math::sign)(fa))
  215. {
  216. if(fabs(a) < tools::min_value<value_type>())
  217. {
  218. // Escape route just in case the answer is zero!
  219. max_iter -= count;
  220. max_iter += 1;
  221. return 0;
  222. }
  223. if(count == 0)
  224. policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, policy_type());
  225. b = a;
  226. fb = fa;
  227. a /= multiplier;
  228. if(a < min_bound)
  229. a = min_bound;
  230. fa = f(a);
  231. --count;
  232. BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
  233. }
  234. }
  235. }
  236. max_iter -= count;
  237. if(fa == 0)
  238. return a;
  239. if(fb == 0)
  240. return b;
  241. //
  242. // Adjust bounds so that if we're looking for an integer
  243. // result, then both ends round the same way:
  244. //
  245. adjust_bounds(a, b, tol);
  246. //
  247. // We don't want zero or denorm lower bounds:
  248. //
  249. if(a < tools::min_value<value_type>())
  250. a = tools::min_value<value_type>();
  251. //
  252. // Go ahead and find the root:
  253. //
  254. std::pair<value_type, value_type> r = toms748_solve(f, a, b, fa, fb, tol, count, policy_type());
  255. max_iter += count;
  256. BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
  257. return (r.first + r.second) / 2;
  258. }
  259. //
  260. // Now finally are the public API functions.
  261. // There is one overload for each policy,
  262. // each one is responsible for selecting the correct
  263. // termination condition, and rounding the result
  264. // to an int where required.
  265. //
  266. template <class Dist>
  267. inline typename Dist::value_type
  268. inverse_discrete_quantile(
  269. const Dist& dist,
  270. const typename Dist::value_type& p,
  271. const typename Dist::value_type& q,
  272. const typename Dist::value_type& guess,
  273. const typename Dist::value_type& multiplier,
  274. const typename Dist::value_type& adder,
  275. const policies::discrete_quantile<policies::real>&,
  276. boost::uintmax_t& max_iter)
  277. {
  278. if(p <= pdf(dist, 0))
  279. return 0;
  280. return do_inverse_discrete_quantile(
  281. dist,
  282. p,
  283. q,
  284. guess,
  285. multiplier,
  286. adder,
  287. tools::eps_tolerance<typename Dist::value_type>(policies::digits<typename Dist::value_type, typename Dist::policy_type>()),
  288. max_iter);
  289. }
  290. template <class Dist>
  291. inline typename Dist::value_type
  292. inverse_discrete_quantile(
  293. const Dist& dist,
  294. const typename Dist::value_type& p,
  295. const typename Dist::value_type& q,
  296. const typename Dist::value_type& guess,
  297. const typename Dist::value_type& multiplier,
  298. const typename Dist::value_type& adder,
  299. const policies::discrete_quantile<policies::integer_round_outwards>&,
  300. boost::uintmax_t& max_iter)
  301. {
  302. typedef typename Dist::value_type value_type;
  303. BOOST_MATH_STD_USING
  304. if(p <= pdf(dist, 0))
  305. return 0;
  306. //
  307. // What happens next depends on whether we're looking for an
  308. // upper or lower quantile:
  309. //
  310. if(p < 0.5f)
  311. return floor(do_inverse_discrete_quantile(
  312. dist,
  313. p,
  314. q,
  315. (guess < 1 ? value_type(1) : (value_type)floor(guess)),
  316. multiplier,
  317. adder,
  318. tools::equal_floor(),
  319. max_iter));
  320. // else:
  321. return ceil(do_inverse_discrete_quantile(
  322. dist,
  323. p,
  324. q,
  325. (value_type)ceil(guess),
  326. multiplier,
  327. adder,
  328. tools::equal_ceil(),
  329. max_iter));
  330. }
  331. template <class Dist>
  332. inline typename Dist::value_type
  333. inverse_discrete_quantile(
  334. const Dist& dist,
  335. const typename Dist::value_type& p,
  336. const typename Dist::value_type& q,
  337. const typename Dist::value_type& guess,
  338. const typename Dist::value_type& multiplier,
  339. const typename Dist::value_type& adder,
  340. const policies::discrete_quantile<policies::integer_round_inwards>&,
  341. boost::uintmax_t& max_iter)
  342. {
  343. typedef typename Dist::value_type value_type;
  344. BOOST_MATH_STD_USING
  345. if(p <= pdf(dist, 0))
  346. return 0;
  347. //
  348. // What happens next depends on whether we're looking for an
  349. // upper or lower quantile:
  350. //
  351. if(p < 0.5f)
  352. return ceil(do_inverse_discrete_quantile(
  353. dist,
  354. p,
  355. q,
  356. ceil(guess),
  357. multiplier,
  358. adder,
  359. tools::equal_ceil(),
  360. max_iter));
  361. // else:
  362. return floor(do_inverse_discrete_quantile(
  363. dist,
  364. p,
  365. q,
  366. (guess < 1 ? value_type(1) : floor(guess)),
  367. multiplier,
  368. adder,
  369. tools::equal_floor(),
  370. max_iter));
  371. }
  372. template <class Dist>
  373. inline typename Dist::value_type
  374. inverse_discrete_quantile(
  375. const Dist& dist,
  376. const typename Dist::value_type& p,
  377. const typename Dist::value_type& q,
  378. const typename Dist::value_type& guess,
  379. const typename Dist::value_type& multiplier,
  380. const typename Dist::value_type& adder,
  381. const policies::discrete_quantile<policies::integer_round_down>&,
  382. boost::uintmax_t& max_iter)
  383. {
  384. typedef typename Dist::value_type value_type;
  385. BOOST_MATH_STD_USING
  386. if(p <= pdf(dist, 0))
  387. return 0;
  388. return floor(do_inverse_discrete_quantile(
  389. dist,
  390. p,
  391. q,
  392. (guess < 1 ? value_type(1) : floor(guess)),
  393. multiplier,
  394. adder,
  395. tools::equal_floor(),
  396. max_iter));
  397. }
  398. template <class Dist>
  399. inline typename Dist::value_type
  400. inverse_discrete_quantile(
  401. const Dist& dist,
  402. const typename Dist::value_type& p,
  403. const typename Dist::value_type& q,
  404. const typename Dist::value_type& guess,
  405. const typename Dist::value_type& multiplier,
  406. const typename Dist::value_type& adder,
  407. const policies::discrete_quantile<policies::integer_round_up>&,
  408. boost::uintmax_t& max_iter)
  409. {
  410. BOOST_MATH_STD_USING
  411. if(p <= pdf(dist, 0))
  412. return 0;
  413. return ceil(do_inverse_discrete_quantile(
  414. dist,
  415. p,
  416. q,
  417. ceil(guess),
  418. multiplier,
  419. adder,
  420. tools::equal_ceil(),
  421. max_iter));
  422. }
  423. template <class Dist>
  424. inline typename Dist::value_type
  425. inverse_discrete_quantile(
  426. const Dist& dist,
  427. const typename Dist::value_type& p,
  428. const typename Dist::value_type& q,
  429. const typename Dist::value_type& guess,
  430. const typename Dist::value_type& multiplier,
  431. const typename Dist::value_type& adder,
  432. const policies::discrete_quantile<policies::integer_round_nearest>&,
  433. boost::uintmax_t& max_iter)
  434. {
  435. typedef typename Dist::value_type value_type;
  436. BOOST_MATH_STD_USING
  437. if(p <= pdf(dist, 0))
  438. return 0;
  439. //
  440. // Note that we adjust the guess to the nearest half-integer:
  441. // this increase the chances that we will bracket the root
  442. // with two results that both round to the same integer quickly.
  443. //
  444. return floor(do_inverse_discrete_quantile(
  445. dist,
  446. p,
  447. q,
  448. (guess < 0.5f ? value_type(1.5f) : floor(guess + 0.5f) + 0.5f),
  449. multiplier,
  450. adder,
  451. tools::equal_nearest_integer(),
  452. max_iter) + 0.5f);
  453. }
  454. }}} // namespaces
  455. #endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE