362 lines · plain
1// Copyright John Maddock 2006.2// Copyright Matt Borland 2024.3// Use, modification and distribution are subject to the4// Boost Software License, Version 1.0. (See accompanying file5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)6 7#ifndef BOOST_STATS_LOGNORMAL_HPP8#define BOOST_STATS_LOGNORMAL_HPP9 10// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3669.htm11// http://mathworld.wolfram.com/LogNormalDistribution.html12// http://en.wikipedia.org/wiki/Lognormal_distribution13 14#include <boost/math/tools/config.hpp>15#include <boost/math/tools/tuple.hpp>16#include <boost/math/tools/promotion.hpp>17#include <boost/math/distributions/fwd.hpp>18#include <boost/math/distributions/normal.hpp>19#include <boost/math/special_functions/expm1.hpp>20#include <boost/math/distributions/detail/common_error_handling.hpp>21#include <boost/math/policies/error_handling.hpp>22#include <boost/math/constants/constants.hpp>23 24namespace boost{ namespace math25{26namespace detail27{28 29 template <class RealType, class Policy>30 BOOST_MATH_GPU_ENABLED inline bool check_lognormal_x(31 const char* function,32 RealType const& x,33 RealType* result, const Policy& pol)34 {35 if((x < 0) || !(boost::math::isfinite)(x))36 {37 *result = policies::raise_domain_error<RealType>(38 function,39 "Random variate is %1% but must be >= 0 !", x, pol);40 return false;41 }42 return true;43 }44 45} // namespace detail46 47 48template <class RealType = double, class Policy = policies::policy<> >49class lognormal_distribution50{51public:52 typedef RealType value_type;53 typedef Policy policy_type;54 55 BOOST_MATH_GPU_ENABLED lognormal_distribution(RealType l_location = 0, RealType l_scale = 1)56 : m_location(l_location), m_scale(l_scale)57 {58 RealType result;59 detail::check_scale("boost::math::lognormal_distribution<%1%>::lognormal_distribution", l_scale, &result, Policy());60 detail::check_location("boost::math::lognormal_distribution<%1%>::lognormal_distribution", l_location, &result, Policy());61 }62 63 BOOST_MATH_GPU_ENABLED RealType location()const64 {65 return m_location;66 }67 68 BOOST_MATH_GPU_ENABLED RealType scale()const69 {70 return m_scale;71 }72private:73 //74 // Data members:75 //76 RealType m_location; // distribution location.77 RealType m_scale; // distribution scale.78};79 80typedef lognormal_distribution<double> lognormal;81 82#ifdef __cpp_deduction_guides83template <class RealType>84lognormal_distribution(RealType)->lognormal_distribution<typename boost::math::tools::promote_args<RealType>::type>;85template <class RealType>86lognormal_distribution(RealType,RealType)->lognormal_distribution<typename boost::math::tools::promote_args<RealType>::type>;87#endif88 89template <class RealType, class Policy>90BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const lognormal_distribution<RealType, Policy>& /*dist*/)91{ // Range of permissible values for random variable x is >0 to +infinity.92 using boost::math::tools::max_value;93 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());94}95 96template <class RealType, class Policy>97BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const lognormal_distribution<RealType, Policy>& /*dist*/)98{ // Range of supported values for random variable x.99 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.100 using boost::math::tools::max_value;101 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());102}103 104template <class RealType, class Policy>105BOOST_MATH_GPU_ENABLED RealType pdf(const lognormal_distribution<RealType, Policy>& dist, const RealType& x)106{107 BOOST_MATH_STD_USING // for ADL of std functions108 109 RealType mu = dist.location();110 RealType sigma = dist.scale();111 112 constexpr auto function = "boost::math::pdf(const lognormal_distribution<%1%>&, %1%)";113 114 RealType result = 0;115 if(0 == detail::check_scale(function, sigma, &result, Policy()))116 return result;117 if(0 == detail::check_location(function, mu, &result, Policy()))118 return result;119 if(0 == detail::check_lognormal_x(function, x, &result, Policy()))120 return result;121 122 if(x == 0)123 return 0;124 125 RealType exponent = log(x) - mu;126 exponent *= -exponent;127 exponent /= 2 * sigma * sigma;128 129 result = exp(exponent);130 result /= sigma * sqrt(2 * constants::pi<RealType>()) * x;131 132 return result;133}134 135template <class RealType, class Policy>136BOOST_MATH_GPU_ENABLED inline RealType cdf(const lognormal_distribution<RealType, Policy>& dist, const RealType& x)137{138 BOOST_MATH_STD_USING // for ADL of std functions139 140 constexpr auto function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)";141 142 RealType result = 0;143 if(0 == detail::check_scale(function, dist.scale(), &result, Policy()))144 return result;145 if(0 == detail::check_location(function, dist.location(), &result, Policy()))146 return result;147 if(0 == detail::check_lognormal_x(function, x, &result, Policy()))148 return result;149 150 if(x == 0)151 return 0;152 153 normal_distribution<RealType, Policy> norm(dist.location(), dist.scale());154 return cdf(norm, log(x));155}156 157template <class RealType, class Policy>158BOOST_MATH_GPU_ENABLED inline RealType quantile(const lognormal_distribution<RealType, Policy>& dist, const RealType& p)159{160 BOOST_MATH_STD_USING // for ADL of std functions161 162 constexpr auto function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)";163 164 RealType result = 0;165 if(0 == detail::check_scale(function, dist.scale(), &result, Policy()))166 return result;167 if(0 == detail::check_location(function, dist.location(), &result, Policy()))168 return result;169 if(0 == detail::check_probability(function, p, &result, Policy()))170 return result;171 172 if(p == 0)173 return 0;174 if(p == 1)175 return policies::raise_overflow_error<RealType>(function, 0, Policy());176 177 normal_distribution<RealType, Policy> norm(dist.location(), dist.scale());178 return exp(quantile(norm, p));179}180 181template <class RealType, class Policy>182BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<lognormal_distribution<RealType, Policy>, RealType>& c)183{184 BOOST_MATH_STD_USING // for ADL of std functions185 186 constexpr auto function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)";187 188 RealType result = 0;189 if(0 == detail::check_scale(function, c.dist.scale(), &result, Policy()))190 return result;191 if(0 == detail::check_location(function, c.dist.location(), &result, Policy()))192 return result;193 if(0 == detail::check_lognormal_x(function, c.param, &result, Policy()))194 return result;195 196 if(c.param == 0)197 return 1;198 199 normal_distribution<RealType, Policy> norm(c.dist.location(), c.dist.scale());200 return cdf(complement(norm, log(c.param)));201}202 203template <class RealType, class Policy>204BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<lognormal_distribution<RealType, Policy>, RealType>& c)205{206 BOOST_MATH_STD_USING // for ADL of std functions207 208 constexpr auto function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)";209 210 RealType result = 0;211 if(0 == detail::check_scale(function, c.dist.scale(), &result, Policy()))212 return result;213 if(0 == detail::check_location(function, c.dist.location(), &result, Policy()))214 return result;215 if(0 == detail::check_probability(function, c.param, &result, Policy()))216 return result;217 218 if(c.param == 1)219 return 0;220 if(c.param == 0)221 return policies::raise_overflow_error<RealType>(function, 0, Policy());222 223 normal_distribution<RealType, Policy> norm(c.dist.location(), c.dist.scale());224 return exp(quantile(complement(norm, c.param)));225}226 227template <class RealType, class Policy>228BOOST_MATH_GPU_ENABLED inline RealType mean(const lognormal_distribution<RealType, Policy>& dist)229{230 BOOST_MATH_STD_USING // for ADL of std functions231 232 RealType mu = dist.location();233 RealType sigma = dist.scale();234 235 RealType result = 0;236 if(0 == detail::check_scale("boost::math::mean(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))237 return result;238 if(0 == detail::check_location("boost::math::mean(const lognormal_distribution<%1%>&)", mu, &result, Policy()))239 return result;240 241 return exp(mu + sigma * sigma / 2);242}243 244template <class RealType, class Policy>245BOOST_MATH_GPU_ENABLED inline RealType variance(const lognormal_distribution<RealType, Policy>& dist)246{247 BOOST_MATH_STD_USING // for ADL of std functions248 249 RealType mu = dist.location();250 RealType sigma = dist.scale();251 252 RealType result = 0;253 if(0 == detail::check_scale("boost::math::variance(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))254 return result;255 if(0 == detail::check_location("boost::math::variance(const lognormal_distribution<%1%>&)", mu, &result, Policy()))256 return result;257 258 return boost::math::expm1(sigma * sigma, Policy()) * exp(2 * mu + sigma * sigma);259}260 261template <class RealType, class Policy>262BOOST_MATH_GPU_ENABLED inline RealType mode(const lognormal_distribution<RealType, Policy>& dist)263{264 BOOST_MATH_STD_USING // for ADL of std functions265 266 RealType mu = dist.location();267 RealType sigma = dist.scale();268 269 RealType result = 0;270 if(0 == detail::check_scale("boost::math::mode(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))271 return result;272 if(0 == detail::check_location("boost::math::mode(const lognormal_distribution<%1%>&)", mu, &result, Policy()))273 return result;274 275 return exp(mu - sigma * sigma);276}277 278template <class RealType, class Policy>279BOOST_MATH_GPU_ENABLED inline RealType median(const lognormal_distribution<RealType, Policy>& dist)280{281 BOOST_MATH_STD_USING // for ADL of std functions282 RealType mu = dist.location();283 return exp(mu); // e^mu284}285 286template <class RealType, class Policy>287BOOST_MATH_GPU_ENABLED inline RealType skewness(const lognormal_distribution<RealType, Policy>& dist)288{289 BOOST_MATH_STD_USING // for ADL of std functions290 291 //RealType mu = dist.location();292 RealType sigma = dist.scale();293 294 RealType ss = sigma * sigma;295 RealType ess = exp(ss);296 297 RealType result = 0;298 if(0 == detail::check_scale("boost::math::skewness(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))299 return result;300 if(0 == detail::check_location("boost::math::skewness(const lognormal_distribution<%1%>&)", dist.location(), &result, Policy()))301 return result;302 303 return (ess + 2) * sqrt(boost::math::expm1(ss, Policy()));304}305 306template <class RealType, class Policy>307BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const lognormal_distribution<RealType, Policy>& dist)308{309 BOOST_MATH_STD_USING // for ADL of std functions310 311 //RealType mu = dist.location();312 RealType sigma = dist.scale();313 RealType ss = sigma * sigma;314 315 RealType result = 0;316 if(0 == detail::check_scale("boost::math::kurtosis(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))317 return result;318 if(0 == detail::check_location("boost::math::kurtosis(const lognormal_distribution<%1%>&)", dist.location(), &result, Policy()))319 return result;320 321 return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 3;322}323 324template <class RealType, class Policy>325BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const lognormal_distribution<RealType, Policy>& dist)326{327 BOOST_MATH_STD_USING // for ADL of std functions328 329 // RealType mu = dist.location();330 RealType sigma = dist.scale();331 RealType ss = sigma * sigma;332 333 RealType result = 0;334 if(0 == detail::check_scale("boost::math::kurtosis_excess(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))335 return result;336 if(0 == detail::check_location("boost::math::kurtosis_excess(const lognormal_distribution<%1%>&)", dist.location(), &result, Policy()))337 return result;338 339 return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 6;340}341 342template <class RealType, class Policy>343BOOST_MATH_GPU_ENABLED inline RealType entropy(const lognormal_distribution<RealType, Policy>& dist)344{345 BOOST_MATH_STD_USING346 RealType mu = dist.location();347 RealType sigma = dist.scale();348 return mu + log(constants::two_pi<RealType>()*constants::e<RealType>()*sigma*sigma)/2;349}350 351} // namespace math352} // namespace boost353 354// This include must be at the end, *after* the accessors355// for this distribution have been defined, in order to356// keep compilers that support two-phase lookup happy.357#include <boost/math/distributions/detail/derived_accessors.hpp>358 359#endif // BOOST_STATS_STUDENTS_T_HPP360 361 362