Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 08:48:00

0001 // boost/math/distributions/arcsine.hpp
0002 
0003 // Copyright John Maddock 2014.
0004 // Copyright Paul A. Bristow 2014.
0005 // Copyright Matt Borland 2024.
0006 
0007 // Use, modification and distribution are subject to the
0008 // Boost Software License, Version 1.0.
0009 // (See accompanying file LICENSE_1_0.txt
0010 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0011 
0012 // http://en.wikipedia.org/wiki/arcsine_distribution
0013 
0014 // The arcsine Distribution is a continuous probability distribution.
0015 // http://en.wikipedia.org/wiki/Arcsine_distribution
0016 // http://www.wolframalpha.com/input/?i=ArcSinDistribution
0017 
0018 // Standard arcsine distribution is a special case of beta distribution with both a & b = one half,
0019 // and 0 <= x <= 1.
0020 
0021 // It is generalized to include any bounded support a <= x <= b from 0 <= x <= 1
0022 // by Wolfram and Wikipedia,
0023 // but using location and scale parameters by
0024 // Virtual Laboratories in Probability and Statistics http://www.math.uah.edu/stat/index.html
0025 // http://www.math.uah.edu/stat/special/Arcsine.html
0026 // The end-point version is simpler and more obvious, so we implement that.
0027 // TODO Perhaps provide location and scale functions?
0028 
0029 
0030 #ifndef BOOST_MATH_DIST_ARCSINE_HPP
0031 #define BOOST_MATH_DIST_ARCSINE_HPP
0032 
0033 #include <boost/math/tools/config.hpp>
0034 #include <boost/math/tools/tuple.hpp>
0035 #include <boost/math/tools/promotion.hpp>
0036 #include <boost/math/distributions/complement.hpp> // complements.
0037 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks.
0038 #include <boost/math/constants/constants.hpp>
0039 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0040 #include <boost/math/policies/policy.hpp>
0041 #include <boost/math/policies/error_handling.hpp>
0042 
0043 #ifndef BOOST_MATH_HAS_NVRTC
0044 #include <boost/math/distributions/fwd.hpp>
0045 #include <cmath>
0046 #include <utility>
0047 #include <exception>  // For std::domain_error.
0048 #endif
0049 
0050 #if defined (BOOST_MSVC)
0051 #  pragma warning(push)
0052 #  pragma warning(disable: 4702) // Unreachable code,
0053 // in domain_error_imp in error_handling.
0054 #endif
0055 
0056 namespace boost
0057 {
0058   namespace math
0059   {
0060     namespace arcsine_detail
0061     {
0062       // Common error checking routines for arcsine distribution functions:
0063       // Duplicating for x_min and x_max provides specific error messages.
0064       template <class RealType, class Policy>
0065       BOOST_MATH_GPU_ENABLED inline bool check_x_min(const char* function, const RealType& x, RealType* result, const Policy& pol)
0066       {
0067         if (!(boost::math::isfinite)(x))
0068         {
0069           *result = policies::raise_domain_error<RealType>(
0070             function,
0071             "x_min argument is %1%, but must be finite !", x, pol);
0072           return false;
0073         }
0074         return true;
0075       } // bool check_x_min
0076 
0077       template <class RealType, class Policy>
0078       BOOST_MATH_GPU_ENABLED inline bool check_x_max(const char* function, const RealType& x, RealType* result, const Policy& pol)
0079       {
0080         if (!(boost::math::isfinite)(x))
0081         {
0082           *result = policies::raise_domain_error<RealType>(
0083             function,
0084             "x_max argument is %1%, but must be finite !", x, pol);
0085           return false;
0086         }
0087         return true;
0088       } // bool check_x_max
0089 
0090 
0091       template <class RealType, class Policy>
0092       BOOST_MATH_GPU_ENABLED inline bool check_x_minmax(const char* function, const RealType& x_min, const RealType& x_max, RealType* result, const Policy& pol)
0093       { // Check x_min < x_max
0094         if (x_min >= x_max)
0095         {
0096           constexpr auto msg = "x_max argument is %1%, but must be > x_min";
0097           *result = policies::raise_domain_error<RealType>(
0098             function,
0099             msg, x_max, pol);
0100             // "x_max argument is %1%, but must be > x_min !", x_max, pol);
0101             // "x_max argument is %1%, but must be > x_min %2!", x_max, x_min, pol); would be better. 
0102             // But would require replication of all helpers functions in /policies/error_handling.hpp for two values,
0103             // as well as two value versions of raise_error, raise_domain_error and do_format
0104           return false;
0105         }
0106         return true;
0107       } // bool check_x_minmax
0108 
0109       template <class RealType, class Policy>
0110       BOOST_MATH_GPU_ENABLED inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
0111       {
0112         if ((p < 0) || (p > 1) || !(boost::math::isfinite)(p))
0113         {
0114           *result = policies::raise_domain_error<RealType>(
0115             function,
0116             "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0117           return false;
0118         }
0119         return true;
0120       } // bool check_prob
0121 
0122       template <class RealType, class Policy>
0123       BOOST_MATH_GPU_ENABLED inline bool check_x(const char* function, const RealType& x_min, const RealType& x_max, const RealType& x, RealType* result, const Policy& pol)
0124       { // Check x finite and x_min < x < x_max.
0125         if (!(boost::math::isfinite)(x))
0126         {
0127           *result = policies::raise_domain_error<RealType>(
0128             function,
0129             "x argument is %1%, but must be finite !", x, pol);
0130           return false;
0131         }
0132         if ((x < x_min) || (x > x_max))
0133         {
0134           // std::cout << x_min << ' ' << x << x_max << std::endl;
0135           *result = policies::raise_domain_error<RealType>(
0136             function,
0137             "x argument is %1%, but must be x_min < x < x_max !", x, pol);
0138           // For example:
0139           // Error in function boost::math::pdf(arcsine_distribution<double> const&, double) : x argument is -1.01, but must be x_min < x < x_max !
0140           // TODO Perhaps show values of x_min and x_max?
0141           return false;
0142         }
0143         return true;
0144       } // bool check_x
0145 
0146       template <class RealType, class Policy>
0147       BOOST_MATH_GPU_ENABLED inline bool check_dist(const char* function, const RealType& x_min, const RealType& x_max, RealType* result, const Policy& pol)
0148       { // Check both x_min and x_max finite, and x_min  < x_max.
0149         return check_x_min(function, x_min, result, pol)
0150             && check_x_max(function, x_max, result, pol)
0151             && check_x_minmax(function, x_min, x_max, result, pol);
0152       } // bool check_dist
0153 
0154       template <class RealType, class Policy>
0155       BOOST_MATH_GPU_ENABLED inline bool check_dist_and_x(const char* function, const RealType& x_min, const RealType& x_max, RealType x, RealType* result, const Policy& pol)
0156       {
0157         return check_dist(function, x_min, x_max, result, pol)
0158           && arcsine_detail::check_x(function, x_min, x_max, x, result, pol);
0159       } // bool check_dist_and_x
0160 
0161       template <class RealType, class Policy>
0162       BOOST_MATH_GPU_ENABLED inline bool check_dist_and_prob(const char* function, const RealType& x_min, const RealType& x_max, RealType p, RealType* result, const Policy& pol)
0163       {
0164         return check_dist(function, x_min, x_max, result, pol)
0165           && check_prob(function, p, result, pol);
0166       } // bool check_dist_and_prob
0167 
0168     } // namespace arcsine_detail
0169 
0170     template <class RealType = double, class Policy = policies::policy<> >
0171     class arcsine_distribution
0172     {
0173     public:
0174       typedef RealType value_type;
0175       typedef Policy policy_type;
0176 
0177       BOOST_MATH_GPU_ENABLED arcsine_distribution(RealType x_min = 0, RealType x_max = 1) : m_x_min(x_min), m_x_max(x_max)
0178       { // Default beta (alpha = beta = 0.5) is standard arcsine with x_min = 0, x_max = 1.
0179         // Generalized to allow x_min and x_max to be specified.
0180         RealType result;
0181         arcsine_detail::check_dist(
0182           "boost::math::arcsine_distribution<%1%>::arcsine_distribution",
0183           m_x_min,
0184           m_x_max,
0185           &result, Policy());
0186       } // arcsine_distribution constructor.
0187       // Accessor functions:
0188       BOOST_MATH_GPU_ENABLED RealType x_min() const
0189       {
0190         return m_x_min;
0191       }
0192       BOOST_MATH_GPU_ENABLED RealType x_max() const
0193       {
0194         return m_x_max;
0195       }
0196 
0197     private:
0198       RealType m_x_min; // Two x min and x max parameters of the arcsine distribution.
0199       RealType m_x_max;
0200     }; // template <class RealType, class Policy> class arcsine_distribution
0201 
0202     // Convenient typedef to construct double version.
0203     typedef arcsine_distribution<double> arcsine;
0204 
0205     #ifdef __cpp_deduction_guides
0206     template <class RealType>
0207     arcsine_distribution(RealType)->arcsine_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0208     template <class RealType>
0209     arcsine_distribution(RealType, RealType)->arcsine_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0210     #endif
0211 
0212     template <class RealType, class Policy>
0213     BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const arcsine_distribution<RealType, Policy>&  dist)
0214     { // Range of permissible values for random variable x.
0215       using boost::math::tools::max_value;
0216       return boost::math::pair<RealType, RealType>(static_cast<RealType>(dist.x_min()), static_cast<RealType>(dist.x_max()));
0217     }
0218 
0219     template <class RealType, class Policy>
0220     BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const arcsine_distribution<RealType, Policy>&  dist)
0221     { // Range of supported values for random variable x.
0222       // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
0223       return boost::math::pair<RealType, RealType>(static_cast<RealType>(dist.x_min()), static_cast<RealType>(dist.x_max()));
0224     }
0225 
0226     template <class RealType, class Policy>
0227     BOOST_MATH_GPU_ENABLED inline RealType mean(const arcsine_distribution<RealType, Policy>& dist)
0228     { // Mean of arcsine distribution .
0229       RealType result;
0230       RealType x_min = dist.x_min();
0231       RealType x_max = dist.x_max();
0232 
0233       if (false == arcsine_detail::check_dist(
0234         "boost::math::mean(arcsine_distribution<%1%> const&, %1% )",
0235         x_min,
0236         x_max,
0237         &result, Policy())
0238         )
0239       {
0240         return result;
0241       }
0242       return  (x_min + x_max) / 2;
0243     } // mean
0244 
0245     template <class RealType, class Policy>
0246     BOOST_MATH_GPU_ENABLED inline RealType variance(const arcsine_distribution<RealType, Policy>& dist)
0247     { // Variance of standard arcsine distribution = (1-0)/8 = 0.125.
0248       RealType result;
0249       RealType x_min = dist.x_min();
0250       RealType x_max = dist.x_max();
0251       if (false == arcsine_detail::check_dist(
0252         "boost::math::variance(arcsine_distribution<%1%> const&, %1% )",
0253         x_min,
0254         x_max,
0255         &result, Policy())
0256         )
0257       {
0258         return result;
0259       }
0260       return  (x_max - x_min) * (x_max - x_min) / 8;
0261     } // variance
0262 
0263     template <class RealType, class Policy>
0264     BOOST_MATH_GPU_ENABLED inline RealType mode(const arcsine_distribution<RealType, Policy>& /* dist */)
0265     { //There are always [*two] values for the mode, at ['x_min] and at ['x_max], default 0 and 1,
0266       // so instead we raise the exception domain_error.
0267       return policies::raise_domain_error<RealType>(
0268         "boost::math::mode(arcsine_distribution<%1%>&)",
0269         "The arcsine distribution has two modes at x_min and x_max: "
0270         "so the return value is %1%.",
0271         std::numeric_limits<RealType>::quiet_NaN(), Policy());
0272     } // mode
0273 
0274     template <class RealType, class Policy>
0275     BOOST_MATH_GPU_ENABLED inline RealType median(const arcsine_distribution<RealType, Policy>& dist)
0276     { // Median of arcsine distribution (a + b) / 2 == mean.
0277       RealType x_min = dist.x_min();
0278       RealType x_max = dist.x_max();
0279       RealType result;
0280       if (false == arcsine_detail::check_dist(
0281         "boost::math::median(arcsine_distribution<%1%> const&, %1% )",
0282         x_min,
0283         x_max,
0284         &result, Policy())
0285         )
0286       {
0287         return result;
0288       }
0289       return  (x_min + x_max) / 2;
0290     }
0291 
0292     template <class RealType, class Policy>
0293     BOOST_MATH_GPU_ENABLED inline RealType skewness(const arcsine_distribution<RealType, Policy>& dist)
0294     {
0295       RealType result;
0296       RealType x_min = dist.x_min();
0297       RealType x_max = dist.x_max();
0298 
0299       if (false == arcsine_detail::check_dist(
0300         "boost::math::skewness(arcsine_distribution<%1%> const&, %1% )",
0301         x_min,
0302         x_max,
0303         &result, Policy())
0304         )
0305       {
0306         return result;
0307       }
0308       return 0;
0309     } // skewness
0310 
0311     template <class RealType, class Policy>
0312     BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const arcsine_distribution<RealType, Policy>& dist)
0313     {
0314       RealType result;
0315       RealType x_min = dist.x_min();
0316       RealType x_max = dist.x_max();
0317 
0318       if (false == arcsine_detail::check_dist(
0319         "boost::math::kurtosis_excess(arcsine_distribution<%1%> const&, %1% )",
0320         x_min,
0321         x_max,
0322         &result, Policy())
0323         )
0324       {
0325         return result;
0326       }
0327       result = -3;
0328       return  result / 2;
0329     } // kurtosis_excess
0330 
0331     template <class RealType, class Policy>
0332     BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const arcsine_distribution<RealType, Policy>& dist)
0333     {
0334       RealType result;
0335       RealType x_min = dist.x_min();
0336       RealType x_max = dist.x_max();
0337 
0338       if (false == arcsine_detail::check_dist(
0339         "boost::math::kurtosis(arcsine_distribution<%1%> const&, %1% )",
0340         x_min,
0341         x_max,
0342         &result, Policy())
0343         )
0344       {
0345         return result;
0346       }
0347 
0348       return 3 + kurtosis_excess(dist);
0349     } // kurtosis
0350 
0351     template <class RealType, class Policy>
0352     BOOST_MATH_GPU_ENABLED inline RealType pdf(const arcsine_distribution<RealType, Policy>& dist, const RealType& xx)
0353     { // Probability Density/Mass Function arcsine.
0354       BOOST_FPU_EXCEPTION_GUARD
0355       BOOST_MATH_STD_USING // For ADL of std functions.
0356 
0357       constexpr auto function = "boost::math::pdf(arcsine_distribution<%1%> const&, %1%)";
0358 
0359       RealType lo = dist.x_min();
0360       RealType hi = dist.x_max();
0361       RealType x = xx;
0362 
0363       // Argument checks:
0364       RealType result = 0; 
0365       if (false == arcsine_detail::check_dist_and_x(
0366         function,
0367         lo, hi, x,
0368         &result, Policy()))
0369       {
0370         return result;
0371       }
0372       using boost::math::constants::pi;
0373       result = static_cast<RealType>(1) / (pi<RealType>() * sqrt((x - lo) * (hi - x)));
0374       return result;
0375     } // pdf
0376 
0377     template <class RealType, class Policy>
0378     BOOST_MATH_GPU_ENABLED inline RealType cdf(const arcsine_distribution<RealType, Policy>& dist, const RealType& x)
0379     { // Cumulative Distribution Function arcsine.
0380       BOOST_MATH_STD_USING // For ADL of std functions.
0381 
0382       constexpr auto function = "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)";
0383 
0384       RealType x_min = dist.x_min();
0385       RealType x_max = dist.x_max();
0386 
0387       // Argument checks:
0388       RealType result = 0;
0389       if (false == arcsine_detail::check_dist_and_x(
0390         function,
0391         x_min, x_max, x,
0392         &result, Policy()))
0393       {
0394         return result;
0395       }
0396       // Special cases:
0397       if (x == x_min)
0398       {
0399         return 0;
0400       }
0401       else if (x == x_max)
0402       {
0403         return 1;
0404       }
0405       using boost::math::constants::pi;
0406       result = static_cast<RealType>(2) * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
0407       return result;
0408     } // arcsine cdf
0409 
0410     template <class RealType, class Policy>
0411     BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<arcsine_distribution<RealType, Policy>, RealType>& c)
0412     { // Complemented Cumulative Distribution Function arcsine.
0413       BOOST_MATH_STD_USING // For ADL of std functions.
0414       constexpr auto function = "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)";
0415 
0416       RealType x = c.param;
0417       arcsine_distribution<RealType, Policy> const& dist = c.dist;
0418       RealType x_min = dist.x_min();
0419       RealType x_max = dist.x_max();
0420 
0421       // Argument checks:
0422       RealType result = 0;
0423       if (false == arcsine_detail::check_dist_and_x(
0424         function,
0425         x_min, x_max, x,
0426         &result, Policy()))
0427       {
0428         return result;
0429       }
0430       if (x == x_min)
0431       {
0432         return 0;
0433       }
0434       else if (x == x_max)
0435       {
0436         return 1;
0437       }
0438       using boost::math::constants::pi;
0439       // Naive version x = 1 - x;
0440       // result = static_cast<RealType>(2) * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
0441       // is less accurate, so use acos instead of asin for complement.
0442       result = static_cast<RealType>(2) * acos(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
0443       return result;
0444     } // arcsine ccdf
0445 
0446     template <class RealType, class Policy>
0447     BOOST_MATH_GPU_ENABLED inline RealType quantile(const arcsine_distribution<RealType, Policy>& dist, const RealType& p)
0448     { 
0449       // Quantile or Percent Point arcsine function or
0450       // Inverse Cumulative probability distribution function CDF.
0451       // Return x (0 <= x <= 1),
0452       // for a given probability p (0 <= p <= 1).
0453       // These functions take a probability as an argument
0454       // and return a value such that the probability that a random variable x
0455       // will be less than or equal to that value
0456       // is whatever probability you supplied as an argument.
0457       BOOST_MATH_STD_USING // For ADL of std functions.
0458 
0459       using boost::math::constants::half_pi;
0460 
0461       constexpr auto function = "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)";
0462 
0463       RealType result = 0; // of argument checks:
0464       RealType x_min = dist.x_min();
0465       RealType x_max = dist.x_max();
0466       if (false == arcsine_detail::check_dist_and_prob(
0467         function,
0468         x_min, x_max, p,
0469         &result, Policy()))
0470       {
0471         return result;
0472       }
0473       // Special cases:
0474       if (p == 0)
0475       {
0476         return 0;
0477       }
0478       if (p == 1)
0479       {
0480         return 1;
0481       }
0482 
0483       RealType sin2hpip = sin(half_pi<RealType>() * p);
0484       RealType sin2hpip2 = sin2hpip * sin2hpip;
0485       result = -x_min * sin2hpip2 + x_min + x_max * sin2hpip2;
0486 
0487       return result;
0488     } // quantile
0489 
0490     template <class RealType, class Policy>
0491     BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<arcsine_distribution<RealType, Policy>, RealType>& c)
0492     { 
0493       // Complement Quantile or Percent Point arcsine function.
0494       // Return the number of expected x for a given
0495       // complement of the probability q.
0496       BOOST_MATH_STD_USING // For ADL of std functions.
0497 
0498       using boost::math::constants::half_pi;
0499       constexpr auto function = "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)";
0500 
0501       // Error checks:
0502       RealType q = c.param;
0503       const arcsine_distribution<RealType, Policy>& dist = c.dist;
0504       RealType result = 0;
0505       RealType x_min = dist.x_min();
0506       RealType x_max = dist.x_max();
0507       if (false == arcsine_detail::check_dist_and_prob(
0508         function,
0509         x_min,
0510         x_max,
0511         q,
0512         &result, Policy()))
0513       {
0514         return result;
0515       }
0516       // Special cases:
0517       if (q == 1)
0518       {
0519         return 0;
0520       }
0521       if (q == 0)
0522       {
0523         return 1;
0524       }
0525       // Naive RealType p = 1 - q; result = sin(half_pi<RealType>() * p); loses accuracy, so use a cos alternative instead.
0526       //result = cos(half_pi<RealType>() * q); // for arcsine(0,1)
0527       //result = result * result;
0528       // For generalized arcsine:
0529       RealType cos2hpip = cos(half_pi<RealType>() * q);
0530       RealType cos2hpip2 = cos2hpip * cos2hpip;
0531       result = -x_min * cos2hpip2 + x_min + x_max * cos2hpip2;
0532 
0533       return result;
0534     } // Quantile Complement
0535 
0536   } // namespace math
0537 } // namespace boost
0538 
0539 // This include must be at the end, *after* the accessors
0540 // for this distribution have been defined, in order to
0541 // keep compilers that support two-phase lookup happy.
0542 #include <boost/math/distributions/detail/derived_accessors.hpp>
0543 
0544 #if defined (BOOST_MSVC)
0545 # pragma warning(pop)
0546 #endif
0547 
0548 #endif // BOOST_MATH_DIST_ARCSINE_HPP