test_out_of_range.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright John Maddock 2012.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_TEST_OUT_OF_RANGE_HPP
  7. #define BOOST_MATH_TEST_OUT_OF_RANGE_HPP
  8. #include <boost/math/special_functions/next.hpp>
  9. #include <boost/test/test_tools.hpp>
  10. /*` check_out_of_range functions check that bad parameters
  11. passed to constructors and functions throw domain_error exceptions.
  12. Usage is `check_out_of_range<DistributionType >(list-of-params);`
  13. Where list-of-params is a list of *valid* parameters from which the distribution can be constructed
  14. - ie the same number of args are passed to the function,
  15. as are passed to the distribution constructor.
  16. Checks:
  17. * Infinity or NaN passed in place of each of the valid params.
  18. * Infinity or NaN as a random variable.
  19. * Out-of-range random variable passed to pdf and cdf (ie outside of "range(distro)").
  20. * Out-of-range probability passed to quantile function and complement.
  21. but does *not* check finite but out-of-range parameters to the constructor
  22. because these are specific to each distribution.
  23. */
  24. #ifdef BOOST_MSVC
  25. #pragma warning(push)
  26. #pragma warning(disable:4127)
  27. #endif
  28. //! \tparam Distro distribution class name, for example: @c students_t_distribution<RealType>.
  29. //! \tparam Infinite only true if support includes infinity (default false means do not allow infinity).
  30. template <class Distro>
  31. void check_support(const Distro& d, bool Infinite = false)
  32. { // Checks that support and function calls are within expected limits.
  33. typedef typename Distro::value_type value_type;
  34. if (Infinite == false)
  35. {
  36. if ((boost::math::isfinite)(range(d).first) && (range(d).first != -boost::math::tools::max_value<value_type>()))
  37. { // If possible, check that a random variable value just less than the bottom of the supported range throws domain errors.
  38. value_type m = (range(d).first == 0) ? -boost::math::tools::min_value<value_type>() : boost::math::float_prior(range(d).first);
  39. BOOST_ASSERT(m != range(d).first);
  40. BOOST_ASSERT(m < range(d).first);
  41. BOOST_MATH_CHECK_THROW(pdf(d, m), std::domain_error);
  42. BOOST_MATH_CHECK_THROW(cdf(d, m), std::domain_error);
  43. BOOST_MATH_CHECK_THROW(cdf(complement(d, m)), std::domain_error);
  44. }
  45. if ((boost::math::isfinite)(range(d).second) && (range(d).second != boost::math::tools::max_value<value_type>()))
  46. { // If possible, check that a random variable value just more than the top of the supported range throws domain errors.
  47. value_type m = (range(d).second == 0) ? boost::math::tools::min_value<value_type>() : boost::math::float_next(range(d).second);
  48. BOOST_ASSERT(m != range(d).first);
  49. BOOST_ASSERT(m > range(d).first);
  50. BOOST_MATH_CHECK_THROW(pdf(d, m), std::domain_error);
  51. BOOST_MATH_CHECK_THROW(cdf(d, m), std::domain_error);
  52. BOOST_MATH_CHECK_THROW(cdf(complement(d, m)), std::domain_error);
  53. }
  54. if (std::numeric_limits<value_type>::has_infinity)
  55. { // Infinity is available,
  56. if ((boost::math::isfinite)(range(d).second))
  57. { // and top of range doesn't include infinity,
  58. // check that using infinity throws domain errors.
  59. BOOST_MATH_CHECK_THROW(pdf(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
  60. BOOST_MATH_CHECK_THROW(cdf(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
  61. BOOST_MATH_CHECK_THROW(cdf(complement(d, std::numeric_limits<value_type>::infinity())), std::domain_error);
  62. }
  63. if ((boost::math::isfinite)(range(d).first))
  64. { // and bottom of range doesn't include infinity,
  65. // check that using infinity throws domain_error exception.
  66. BOOST_MATH_CHECK_THROW(pdf(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
  67. BOOST_MATH_CHECK_THROW(cdf(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
  68. BOOST_MATH_CHECK_THROW(cdf(complement(d, -std::numeric_limits<value_type>::infinity())), std::domain_error);
  69. }
  70. // Check that using infinity with quantiles always throws domain_error exception.
  71. BOOST_MATH_CHECK_THROW(quantile(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
  72. BOOST_MATH_CHECK_THROW(quantile(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
  73. BOOST_MATH_CHECK_THROW(quantile(complement(d, std::numeric_limits<value_type>::infinity())), std::domain_error);
  74. BOOST_MATH_CHECK_THROW(quantile(complement(d, -std::numeric_limits<value_type>::infinity())), std::domain_error);
  75. }
  76. }
  77. if(std::numeric_limits<value_type>::has_quiet_NaN)
  78. { // NaN is available.
  79. BOOST_MATH_CHECK_THROW(pdf(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  80. BOOST_MATH_CHECK_THROW(cdf(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  81. BOOST_MATH_CHECK_THROW(cdf(complement(d, std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
  82. BOOST_MATH_CHECK_THROW(pdf(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  83. BOOST_MATH_CHECK_THROW(cdf(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  84. BOOST_MATH_CHECK_THROW(cdf(complement(d, -std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
  85. BOOST_MATH_CHECK_THROW(quantile(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  86. BOOST_MATH_CHECK_THROW(quantile(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
  87. BOOST_MATH_CHECK_THROW(quantile(complement(d, std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
  88. BOOST_MATH_CHECK_THROW(quantile(complement(d, -std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
  89. }
  90. // Check that using probability outside [0,1] with quantiles always throws domain_error exception.
  91. BOOST_MATH_CHECK_THROW(quantile(d, -1), std::domain_error);
  92. BOOST_MATH_CHECK_THROW(quantile(d, 2), std::domain_error);
  93. BOOST_MATH_CHECK_THROW(quantile(complement(d, -1)), std::domain_error);
  94. BOOST_MATH_CHECK_THROW(quantile(complement(d, 2)), std::domain_error);
  95. }
  96. // Four check_out_of_range versions for distributions with zero to 3 constructor parameters.
  97. template <class Distro>
  98. void check_out_of_range()
  99. {
  100. Distro d;
  101. check_support(d);
  102. }
  103. template <class Distro>
  104. void check_out_of_range(typename Distro::value_type p1)
  105. {
  106. typedef typename Distro::value_type value_type;
  107. Distro d(p1);
  108. check_support(d);
  109. if(std::numeric_limits<value_type>::has_infinity)
  110. {
  111. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
  112. // BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity()), range(d).second), std::domain_error);
  113. }
  114. if(std::numeric_limits<value_type>::has_quiet_NaN)
  115. {
  116. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
  117. }
  118. }
  119. template <class Distro>
  120. void check_out_of_range(typename Distro::value_type p1, typename Distro::value_type p2)
  121. {
  122. typedef typename Distro::value_type value_type;
  123. Distro d(p1, p2);
  124. check_support(d);
  125. if(std::numeric_limits<value_type>::has_infinity)
  126. {
  127. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity(), p2), range(d).first), std::domain_error);
  128. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
  129. }
  130. if(std::numeric_limits<value_type>::has_quiet_NaN)
  131. {
  132. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN(), p2), range(d).first), std::domain_error);
  133. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
  134. }
  135. }
  136. template <class Distro>
  137. void check_out_of_range(typename Distro::value_type p1, typename Distro::value_type p2, typename Distro::value_type p3)
  138. {
  139. typedef typename Distro::value_type value_type;
  140. Distro d(p1, p2, p3);
  141. check_support(d);
  142. if(std::numeric_limits<value_type>::has_infinity)
  143. {
  144. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity(), p2, p3), range(d).first), std::domain_error);
  145. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::infinity(), p3), range(d).first), std::domain_error);
  146. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, p2, std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
  147. }
  148. if(std::numeric_limits<value_type>::has_quiet_NaN)
  149. {
  150. BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN(), p2, p3), range(d).first), std::domain_error);
  151. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::quiet_NaN(), p3), range(d).first), std::domain_error);
  152. BOOST_MATH_CHECK_THROW(pdf(Distro(p1, p2, std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
  153. }
  154. }
  155. #ifdef BOOST_MSVC
  156. #pragma warning(pop)
  157. #endif
  158. #endif // BOOST_MATH_TEST_OUT_OF_RANGE_HPP