RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
noncentral_t.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <span>
5
14
15namespace randlib
16{
17
26template <typename RealType>
27class NoncentralTRand final : public ContinuousDistribution<RealType>
28{
29 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
30 void sample(detail::EngineRef g, std::span<RealType> outputData) const override;
31
32 double nu = 1;
33 double delta = 0;
34 double halfNu = 0.5;
35 double halfDeltaSquared = 0;
36 int seriesCenter = 0;
37 StudentTRand<RealType> central{};
38 NakagamiRand<RealType> denominator{};
39
40 long double integralPositiveTail(long double x, long double noncentrality, bool upper) const;
41 long double integralDensity(long double x) const;
42 static long double kummerM(long double a, long double b, long double z);
43 long double logPositiveNormalMoment(long double power, long double noncentrality) const;
44 long double asymptoticLogTail(long double x, long double noncentrality, bool density) const;
45 long double positiveTail(long double x, long double noncentrality, bool upper, bool allowIntegral) const;
46 long double probability(long double x, bool upper, bool allowIntegral = true) const;
47 long double inverseDenominatorMoment(int order) const;
48
49public:
50 explicit NoncentralTRand(double degree = 1, double noncentrality = 0);
51
52 [[nodiscard]] std::string Name() const override;
53 [[nodiscard]] Support SupportType() const override { return Support::Infinite; }
54 [[nodiscard]] RealType MinValue() const override { return -INFINITY; }
55 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
56
57 void SetParameters(double degree, double noncentrality);
58 [[nodiscard]] double GetDegree() const noexcept { return nu; }
59 [[nodiscard]] double GetNoncentrality() const noexcept { return delta; }
60
61 [[nodiscard]] double f(const RealType &x) const override;
62 [[nodiscard]] double logf(const RealType &x) const override;
63 [[nodiscard]] double F(const RealType &x) const override;
64 [[nodiscard]] double S(const RealType &x) const override;
65
66 template <std::uniform_random_bit_generator G>
67 [[nodiscard]] RealType operator()(G &g) const;
68
69 [[nodiscard]] long double Mean() const override;
70 [[nodiscard]] long double Variance() const override;
71 [[nodiscard]] long double Skewness() const override;
72 [[nodiscard]] long double ExcessKurtosis() const override;
73
74private:
75 RealType quantileImpl(double p) const override;
76 RealType quantileImpl1m(double p) const override;
77 std::complex<double> CFImpl(double t) const override;
78};
79
80} // namespace randlib
81
83
84namespace randlib
85{
86
87template <typename RealType>
88NoncentralTRand<RealType>::NoncentralTRand(double degree, double noncentrality)
89{
90 SetParameters(degree, noncentrality);
91}
92
93template <typename RealType>
95{
96 return "Noncentral-t(" + this->toStringWithPrecision(nu) + ", " + this->toStringWithPrecision(delta) + ")";
97}
98
99template <typename RealType>
100void NoncentralTRand<RealType>::SetParameters(double degree, double noncentrality)
101{
102 if (!(degree > 0) || !std::isfinite(degree))
103 throw std::invalid_argument("Noncentral-t distribution: degree should be finite and positive");
104 if (!std::isfinite(noncentrality))
105 throw std::invalid_argument("Noncentral-t distribution: noncentrality should be finite");
106 nu = degree;
107 delta = noncentrality;
108 halfNu = 0.5 * nu;
109 halfDeltaSquared = 0.5 * delta * delta;
110 seriesCenter = (std::isfinite(halfDeltaSquared) && halfDeltaSquared < 1000000)
111 ? static_cast<int>(std::floor(halfDeltaSquared))
112 : -1;
113 central.SetDegree(nu);
114 denominator.SetParameters(halfNu, 1.0);
115}
116
117template <typename RealType>
118long double NoncentralTRand<RealType>::integralPositiveTail(long double x, long double noncentrality, bool upper) const
119{
120 const long double shape = halfNu;
121 const long double logCoefficient = randlib::consts::ln2 + shape * std::log(shape) - std::lgamma(shape);
122 const long double inverseSqrt2 = 1 / std::sqrt(2.0L);
123 return math::integrate<long double>(
124 [=](long double w) {
125 if (!(w > 0))
126 return 0.0L;
127 const long double normalProbability =
128 0.5L * std::erfc((upper ? x * w - noncentrality : noncentrality - x * w) * inverseSqrt2);
129 if (normalProbability == 0)
130 return 0.0L;
131 const long double logDensity = logCoefficient + (2 * shape - 1) * std::log(w) - shape * w * w;
132 return normalProbability * std::exp(logDensity);
133 },
134 0.0L, std::numeric_limits<long double>::infinity(), 2e-13L, 2048);
135}
136
137template <typename RealType>
138long double NoncentralTRand<RealType>::integralDensity(long double x) const
139{
140 const long double shape = halfNu;
141 const long double noncentrality = delta;
142 const long double logCoefficient =
143 randlib::consts::ln2 + shape * std::log(shape) - std::lgamma(shape) - 0.5L * std::log(2 * randlib::consts::pi);
144 const auto integrand = [=](long double w) {
145 if (!(w > 0))
146 return 0.0L;
147 const long double normalArgument = x * w - noncentrality;
148 const long double logIntegrand =
149 logCoefficient + 2 * shape * std::log(w) - shape * w * w - 0.5L * normalArgument * normalArgument;
150 return std::exp(logIntegrand);
151 };
152 const long double quadratic = x * x + 2 * shape;
153 const long double saddle =
154 (x * noncentrality + std::sqrt(x * x * noncentrality * noncentrality + 8 * shape * quadratic)) /
155 (2 * quadratic);
156 return math::integrate<long double>(integrand, 0.0L, saddle, 2e-13L, 1024) +
157 math::integrate<long double>(integrand, saddle, std::numeric_limits<long double>::infinity(), 2e-13L, 1024);
158}
159
160template <typename RealType>
161long double NoncentralTRand<RealType>::kummerM(long double a, long double b, long double z)
162{
163 long double term = 1;
164 long double sum = 1;
165 for (int n = 1; n < 100000; ++n) {
166 term *= (a + n - 1) / (b + n - 1) * z / n;
167 sum += term;
168 if (std::fabs(term) <= 4 * std::numeric_limits<long double>::epsilon() * std::fabs(sum))
169 break;
170 }
171 return sum;
172}
173
174template <typename RealType>
175long double NoncentralTRand<RealType>::logPositiveNormalMoment(long double power, long double noncentrality) const
176{
177 const long double saddle = 0.5L * (noncentrality + std::sqrt(noncentrality * noncentrality + 4 * power));
178 const long double logPeak = power * std::log(saddle) - 0.5L * (saddle - noncentrality) * (saddle - noncentrality) -
179 0.5L * std::log(2 * randlib::consts::pi);
180 const auto integrand = [=](long double value) {
181 if (!(value > 0))
182 return 0.0L;
183 const long double difference = value - noncentrality;
184 const long double logValue =
185 power * std::log(value) - 0.5L * difference * difference - 0.5L * std::log(2 * randlib::consts::pi);
186 return std::exp(logValue - logPeak);
187 };
188 const long double scaled =
189 math::integrate<long double>(integrand, 0.0L, saddle, 2e-13L, 512) +
190 math::integrate<long double>(integrand, saddle, std::numeric_limits<long double>::infinity(), 2e-13L, 512);
191 return logPeak + std::log(scaled);
192}
193
194template <typename RealType>
195long double NoncentralTRand<RealType>::asymptoticLogTail(long double x, long double noncentrality, bool density) const
196{
197 const long double b = halfNu;
198 const long double logX = std::log(x);
199 std::array<long double, 8> logarithms{};
200 long double maximum = -INFINITY;
201 int terms = 0;
202 for (int k = 0; k < static_cast<int>(logarithms.size()); ++k) {
203 const long double power = nu + 2 * k;
204 long double logarithm = (b + k) * std::log(b) - std::lgamma(b) - std::lgamma(k + 1.0L) - std::log(b + k) +
205 logPositiveNormalMoment(power, noncentrality) - power * logX;
206 if (density)
207 logarithm += std::log(power) - logX;
208 logarithms[k] = logarithm;
209 maximum = std::max(maximum, logarithm);
210 terms = k + 1;
211 if (k >= 2 && logarithm < maximum - 40)
212 break;
213 }
214 long double scaled = 0;
215 for (int k = 0; k < terms; ++k)
216 scaled += ((k % 2 == 0) ? 1 : -1) * std::exp(logarithms[k] - maximum);
217 return maximum + std::log(scaled);
218}
219
220template <typename RealType>
221long double NoncentralTRand<RealType>::positiveTail(long double x, long double noncentrality, bool upper,
222 bool allowIntegral) const
223{
224 if (x == 0)
225 return 0.5L * std::erfc((upper ? -noncentrality : noncentrality) / std::sqrt(2.0L));
226 if (std::isinf(x))
227 return upper ? 0.0L : 1.0L;
228 const long double lambda = 0.5L * noncentrality * noncentrality;
229 if (lambda == 0)
230 return upper ? central.S(static_cast<RealType>(x)) : central.F(static_cast<RealType>(x));
231 const long double asymptoticCrossover = std::max(100.0L, 10 * std::fabs(noncentrality) + 10);
232 if (x > asymptoticCrossover) {
233 const long double tail = std::exp(asymptoticLogTail(x, noncentrality, false));
234 return upper ? tail : 1 - tail;
235 }
236 if (seriesCenter < 0)
237 return integralPositiveTail(x, noncentrality, upper);
238
239 const long double logRatio = 2 * std::log(x) - std::log(static_cast<long double>(nu));
240 const long double logY = -math::softplus(-logRatio);
241 const long double log1mY = -math::softplus(logRatio);
242 const long double y = std::exp(logY);
243 const long double oneMinusY = std::exp(log1mY);
244 const long double b = halfNu;
245 const int center = seriesCenter;
246 long double a1 = center + 0.5L;
247 long double a2 = center + 1.0L;
248 const long double logBeta1 = math::logBeta(a1, b);
249 const long double logBeta2 = math::logBeta(a2, b);
250 long double beta1 =
251 upper ? math::ibeta(oneMinusY, b, a1, logBeta1, log1mY, logY) : math::ibeta(y, a1, b, logBeta1, logY, log1mY);
252 long double beta2 =
253 upper ? math::ibeta(oneMinusY, b, a2, logBeta2, log1mY, logY) : math::ibeta(y, a2, b, logBeta2, logY, log1mY);
254 long double increment1 = std::exp(a1 * logY + b * log1mY - std::log(a1) - logBeta1);
255 long double increment2 = std::exp(a2 * logY + b * log1mY - std::log(a2) - logBeta2);
256 const auto centerValue = static_cast<long double>(center);
257 const long double logPoisson = (center == 0) ? -lambda
258 : -math::stirlingError<long double>(static_cast<std::size_t>(center)) -
259 math::bd0<long double>(centerValue, lambda) -
260 0.5L * std::log(2 * randlib::consts::pi * centerValue);
261 long double poisson = std::exp(logPoisson);
262 const long double gammaRatio = std::exp(math::logBeta(centerValue + 1, 0.5L) - 0.5L * randlib::consts::lnpi);
263 long double odd = std::copysign(std::sqrt(lambda) * gammaRatio * poisson, noncentrality);
264 long double sum = poisson * beta1 + odd * beta2;
265 long double compensation = 0;
266 long double absoluteSum = std::fabs(poisson * beta1) + std::fabs(odd * beta2);
267 const auto addTerm = [&](long double term) {
268 const long double corrected = term - compensation;
269 const long double next = sum + corrected;
270 compensation = (next - sum) - corrected;
271 sum = next;
272 };
273
274 long double lowerPoisson = poisson;
275 long double lowerOdd = odd;
276 long double lowerBeta1 = beta1;
277 long double lowerBeta2 = beta2;
278 long double lowerIncrement1 = increment1;
279 long double lowerIncrement2 = increment2;
280 long double lowerA1 = a1;
281 long double lowerA2 = a2;
282 for (int j = center; j > 0; --j) {
283 const long double previousIncrement1 = lowerIncrement1 * lowerA1 / (y * (lowerA1 - 1 + b));
284 const long double previousIncrement2 = lowerIncrement2 * lowerA2 / (y * (lowerA2 - 1 + b));
285 lowerBeta1 += upper ? -previousIncrement1 : previousIncrement1;
286 lowerBeta2 += upper ? -previousIncrement2 : previousIncrement2;
287 lowerA1 -= 1;
288 lowerA2 -= 1;
289 lowerIncrement1 = previousIncrement1;
290 lowerIncrement2 = previousIncrement2;
291 lowerPoisson *= j / lambda;
292 lowerOdd *= (j + 0.5L) / lambda;
293 const long double term = lowerPoisson * lowerBeta1 + lowerOdd * lowerBeta2;
294 addTerm(term);
295 absoluteSum += std::fabs(lowerPoisson * lowerBeta1) + std::fabs(lowerOdd * lowerBeta2);
296 }
297
298 int decreasing = 0;
299 for (int j = center + 1; j < center + 1000000; ++j) {
300 poisson *= lambda / j;
301 odd *= lambda / (j + 0.5L);
302 beta1 += upper ? increment1 : -increment1;
303 beta2 += upper ? increment2 : -increment2;
304 increment1 *= y * (a1 + b) / (a1 + 1);
305 increment2 *= y * (a2 + b) / (a2 + 1);
306 a1 += 1;
307 a2 += 1;
308 const long double term = poisson * beta1 + odd * beta2;
309 const long double bound = std::fabs(poisson * beta1) + std::fabs(odd * beta2);
310 addTerm(term);
311 absoluteSum += bound;
312 decreasing = (bound <= 8 * std::numeric_limits<long double>::epsilon() * absoluteSum) ? decreasing + 1 : 0;
313 if (decreasing >= 4)
314 break;
315 }
316
317 long double result = 0.5L * sum;
318 if (!upper)
319 result += 0.5L * std::erfc(noncentrality / std::sqrt(2.0L));
320 const long double integralCrossover = std::max(50.0L, 10 * std::fabs(noncentrality) + 10);
321 if (allowIntegral && upper && noncentrality < 0 &&
322 (result <= 0 || result <= 256 * std::numeric_limits<long double>::epsilon() * absoluteSum ||
323 (result < 1e-8L && x < integralCrossover)))
324 result = integralPositiveTail(x, noncentrality, true);
325 if (!std::isfinite(result) || result < 0 || result > 1)
326 result = integralPositiveTail(x, noncentrality, upper);
327 return std::clamp(result, 0.0L, 1.0L);
328}
329
330template <typename RealType>
331long double NoncentralTRand<RealType>::probability(long double x, bool upper, bool allowIntegral) const
332{
333 if (x == 0)
334 return 0.5L * std::erfc((upper ? -delta : delta) / std::sqrt(2.0L));
335 if (x > 0)
336 return positiveTail(x, delta, upper, allowIntegral);
337 return positiveTail(-x, -delta, !upper, allowIntegral);
338}
339
340template <typename RealType>
341double NoncentralTRand<RealType>::F(const RealType &x) const
342{
343 return static_cast<double>(probability(x, false));
344}
345
346template <typename RealType>
347double NoncentralTRand<RealType>::S(const RealType &x) const
348{
349 return static_cast<double>(probability(x, true));
350}
351
352template <typename RealType>
353double NoncentralTRand<RealType>::f(const RealType &x) const
354{
355 if (!std::isfinite(x))
356 return 0;
357 if (delta == 0)
358 return central.f(x);
359 if (x == 0)
360 return std::exp(logf(x));
361 const long double reflectedNoncentrality = (x > 0) ? delta : -delta;
362 const long double asymptoticCrossover = std::max(100.0L, 10 * std::fabs(reflectedNoncentrality) + 10);
363 if (std::fabs(static_cast<long double>(x)) > asymptoticCrossover) {
364 return static_cast<double>(
365 std::exp(asymptoticLogTail(std::fabs(static_cast<long double>(x)), reflectedNoncentrality, true)));
366 }
367 const long double square = static_cast<long double>(x) * x;
368 const long double halfDegree = 0.5L * nu;
369 const long double z = halfDeltaSquared * square / (square + nu);
370 const long double a = 0.5L * (nu + 1);
371 const long double summit = 0.5L * (std::sqrt(z * (4 * a + z)) + z);
372 if (summit < 40) {
373 const long double first = kummerM(a, 0.5L, z);
374 long double second = kummerM(halfDegree + 1, 1.5L, z);
375 second *= std::exp(std::lgamma(halfDegree + 1) - std::lgamma(a));
376 second *= std::sqrt(2.0L) * delta * static_cast<long double>(x) / std::sqrt(square + nu);
377 const long double series = first + second;
378 if (series > 4 * std::sqrt(std::numeric_limits<long double>::epsilon()) * first) {
379 const long double logCoefficient = -halfDeltaSquared - a * std::log1p(square / nu) + std::lgamma(a) -
380 std::lgamma(halfDegree) - 0.5L * std::log(nu * randlib::consts::pi);
381 return static_cast<double>(std::exp(logCoefficient) * series);
382 }
383 }
384 if (static_cast<long double>(x) * delta < 0)
385 return static_cast<double>(integralDensity(x));
386 const long double scaledX = static_cast<long double>(x) * std::sqrt(1 + 2 / nu);
387 const NoncentralTRand<RealType> shifted(nu + 2, delta);
388 const long double first = (x > 0) ? probability(x, true, false) : shifted.probability(scaledX, false, false);
389 const long double second = (x > 0) ? shifted.probability(scaledX, true, false) : probability(x, false, false);
390 const long double difference = first - second;
391 if (!(difference > std::sqrt(std::numeric_limits<long double>::epsilon()) * (std::fabs(first) + std::fabs(second))))
392 return static_cast<double>(integralDensity(x));
393 return static_cast<double>(nu / static_cast<long double>(x) * difference);
394}
395
396template <typename RealType>
397double NoncentralTRand<RealType>::logf(const RealType &x) const
398{
399 if (!std::isfinite(x))
400 return -INFINITY;
401 if (delta == 0)
402 return central.logf(x);
403 if (x == 0)
404 return static_cast<double>(std::lgamma(0.5L * (nu + 1)) - std::lgamma(0.5L * nu) -
405 0.5L * std::log(static_cast<long double>(nu) * randlib::consts::pi) -
406 halfDeltaSquared);
407 const long double reflectedNoncentrality = (x > 0) ? delta : -delta;
408 const long double asymptoticCrossover = std::max(100.0L, 10 * std::fabs(reflectedNoncentrality) + 10);
409 if (std::fabs(static_cast<long double>(x)) > asymptoticCrossover) {
410 return static_cast<double>(
411 asymptoticLogTail(std::fabs(static_cast<long double>(x)), reflectedNoncentrality, true));
412 }
413 const double density = f(x);
414 return (density > 0) ? std::log(density) : -INFINITY;
415}
416
417template <typename RealType>
418template <std::uniform_random_bit_generator G>
420{
421 return (static_cast<RealType>(delta) + detail::standardNormal<RealType>(g)) / denominator(g);
422}
423
424template <typename RealType>
425void NoncentralTRand<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
426{
427 denominator.Sample(g, outputData);
428 for (RealType &value : outputData)
429 value = (static_cast<RealType>(delta) + detail::standardNormal<RealType>(g)) / value;
430}
431
432template <typename RealType>
433long double NoncentralTRand<RealType>::inverseDenominatorMoment(int order) const
434{
435 const long double halfOrder = 0.5L * order;
436 const long double halfDegree = halfNu;
437 if (order == 2)
438 return halfDegree / (halfDegree - 1);
439 if (order == 4)
440 return halfDegree * halfDegree / ((halfDegree - 1) * (halfDegree - 2));
441 const long double logRatio = math::logBeta(halfDegree - halfOrder, halfOrder) - std::lgamma(halfOrder);
442 return std::exp(halfOrder * std::log(halfDegree) + logRatio);
443}
444
445template <typename RealType>
447{
448 return (nu > 1) ? delta * inverseDenominatorMoment(1) : NAN;
449}
450
451template <typename RealType>
453{
454 if (nu <= 2)
455 return (nu > 1) ? INFINITY : NAN;
456 const long double first = inverseDenominatorMoment(1);
457 const long double second = inverseDenominatorMoment(2);
458 const long double dispersion = std::fma(-first, first, second);
459 return std::fma(static_cast<long double>(delta) * delta, dispersion, second);
460}
461
462template <typename RealType>
464{
465 if (nu <= 3)
466 return NAN;
467 const long double first = inverseDenominatorMoment(1);
468 const long double second = inverseDenominatorMoment(2);
469 const long double third = inverseDenominatorMoment(3);
470 const long double dispersion = std::fma(-first, first, second);
471 const long double thirdDifference = std::fma(-first, second, third);
472 const long double thirdCoefficient = std::fma(-2 * first, dispersion, thirdDifference);
473 const long double squaredDelta = static_cast<long double>(delta) * delta;
474 const long double variance = std::fma(squaredDelta, dispersion, second);
475 const long double centralThird = delta * std::fma(squaredDelta, thirdCoefficient, 3 * thirdDifference);
476 return centralThird / std::pow(variance, 1.5L);
477}
478
479template <typename RealType>
481{
482 if (nu <= 4)
483 return (nu > 2) ? INFINITY : NAN;
484 const long double first = inverseDenominatorMoment(1);
485 const long double second = inverseDenominatorMoment(2);
486 const long double third = inverseDenominatorMoment(3);
487 const long double fourth = inverseDenominatorMoment(4);
488 const long double dispersion = std::fma(-first, first, second);
489 const long double thirdDifference = std::fma(-first, second, third);
490 const long double fourthDifference = std::fma(-first, third, fourth);
491 const long double squaredCoefficient = std::fma(-first, thirdDifference, fourthDifference);
492 const long double fourthCoefficient =
493 std::fma(-3 * first, std::fma(-first, dispersion, thirdDifference), fourthDifference);
494 const long double squaredDelta = static_cast<long double>(delta) * delta;
495 const long double variance = std::fma(squaredDelta, dispersion, second);
496 const long double centralFourth = std::fma(squaredDelta * squaredDelta, fourthCoefficient,
497 std::fma(6 * squaredDelta, squaredCoefficient, 3 * fourth));
498 return centralFourth / (variance * variance) - 3;
499}
500
501template <typename RealType>
502RealType NoncentralTRand<RealType>::quantileImpl(double p) const
503{
504 if (delta == 0)
505 return central.Quantile(p);
506 if (p == static_cast<double>(probability(0, false)))
507 return 0;
508 const long double mean = Mean();
509 const RealType guess = std::isfinite(mean) ? static_cast<RealType>(mean) : static_cast<RealType>(delta);
511}
512
513template <typename RealType>
514RealType NoncentralTRand<RealType>::quantileImpl1m(double p) const
515{
516 if (delta == 0)
517 return central.Quantile1m(p);
518 if (p == static_cast<double>(probability(0, true)))
519 return 0;
520 const long double mean = Mean();
521 const RealType guess = std::isfinite(mean) ? static_cast<RealType>(mean) : static_cast<RealType>(delta);
523}
524
525template <typename RealType>
526std::complex<double> NoncentralTRand<RealType>::CFImpl(double t) const
527{
528 if (delta == 0)
529 return central.CF(t);
530 const long double frequency = t;
531 const long double noncentrality = delta;
532 const long double shape = halfNu;
533 const long double logCoefficient = randlib::consts::ln2 + shape * std::log(shape) - std::lgamma(shape);
534 const long double linear = 2 * shape - 1;
535 const long double squaredMode =
536 (linear + std::sqrt(linear * linear + 8 * shape * frequency * frequency)) / (4 * shape);
537 const long double mode = std::sqrt(squaredMode);
538 const auto envelope = [logCoefficient, linear, shape, frequency](long double w) {
539 if (!(w > 0))
540 return 0.0L;
541 return std::exp(logCoefficient + linear * std::log(w) - shape * w * w - 0.5L * frequency * frequency / (w * w));
542 };
543 const auto integratePart = [envelope, frequency, noncentrality, mode](bool imaginary) {
544 const auto integrand = [envelope, frequency, noncentrality, imaginary](long double w) {
545 const long double amplitude = envelope(w);
546 if (amplitude == 0)
547 return 0.0L;
548 const long double phase = frequency * noncentrality / w;
549 return amplitude * (imaginary ? std::sin(phase) : std::cos(phase));
550 };
551 return math::integrate<long double>(integrand, 0.0L, mode, 2e-12L, 1024) +
552 math::integrate<long double>(integrand, mode, std::numeric_limits<long double>::infinity(), 2e-12L,
553 1024);
554 };
555 return {static_cast<double>(integratePart(false)), static_cast<double>(integratePart(true))};
556}
557
558} // namespace randlib
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
RealType quantileImpl(double p, RealType initValue) const override
Definition continuous.hpp:140
RealType quantileImpl1m(double p, RealType initValue) const override
Definition continuous.hpp:152
The NakagamiRand class Nakagami distribution.
Definition nakagami.hpp:96
Noncentral Student's t-distribution.
Definition noncentral_t.hpp:28
double S(const RealType &x) const override
Definition noncentral_t.hpp:347
long double ExcessKurtosis() const override
Definition noncentral_t.hpp:480
RealType MinValue() const override
Definition noncentral_t.hpp:54
long double Variance() const override
Definition noncentral_t.hpp:452
double GetDegree() const noexcept
Definition noncentral_t.hpp:58
RealType MaxValue() const override
Definition noncentral_t.hpp:55
RealType operator()(G &g) const
Definition noncentral_t.hpp:419
Support SupportType() const override
Definition noncentral_t.hpp:53
double F(const RealType &x) const override
Definition noncentral_t.hpp:341
double GetNoncentrality() const noexcept
Definition noncentral_t.hpp:59
long double Mean() const override
Definition noncentral_t.hpp:446
std::string Name() const override
Definition noncentral_t.hpp:94
NoncentralTRand(double degree=1, double noncentrality=0)
Definition noncentral_t.hpp:88
void SetParameters(double degree, double noncentrality)
Definition noncentral_t.hpp:100
double logf(const RealType &x) const override
Definition noncentral_t.hpp:397
long double Skewness() const override
Definition noncentral_t.hpp:463
double f(const RealType &x) const override
Definition noncentral_t.hpp:353
void Sample(std::span< T > outputData) const
Fills the output with variates drawn with the engine of this object.
Definition distribution.hpp:139
The StudentTRand class Student's t-distribution.
Definition student_t.hpp:22
T Quantile(double p) const
Definition univariate.hpp:307
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
constexpr long double ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double lnpi
Definition constants.hpp:21
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
Real logBeta(Real a, std::type_identity_t< Real > b)
Calculate logarithm of beta function.
Definition math/beta.hpp:72
Real bd0(std::type_identity_t< Real > x, Real m)
Deviance term of the saddle-point expansions of Poisson and binomial probabilities (C.
Definition math/gamma.hpp:620
Real stirlingError(size_t n)
Definition math/gamma.hpp:598
Real softplus(Real x)
Definition functions.hpp:252
Real ibeta(Real x, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > logBetaFun, std::type_identity_t< Real > logX, std::type_identity_t< Real > log1mX)
Fast calculation of regularized beta function, using precalculated values.
Definition math/beta.hpp:250
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ Infinite
(-∞, ∞)