|
| 1 | +#include <cmath> |
| 2 | +#include <limits> |
| 3 | +#include <vector> |
| 4 | +#include <gtest/gtest.h> |
| 5 | +#include <test/unit/math/expect_near_rel.hpp> |
| 6 | +#include <stan/math/prim.hpp> |
| 7 | +#include <stan/math/prim/fun/lgamma_stirling_diff.hpp> |
| 8 | + |
| 9 | +TEST(MathFunctions, lgamma_stirling_diff_errors_special_cases) { |
| 10 | + using stan::math::lgamma_stirling_diff; |
| 11 | + |
| 12 | + double nan = std::numeric_limits<double>::quiet_NaN(); |
| 13 | + double inf = std::numeric_limits<double>::infinity(); |
| 14 | + |
| 15 | + EXPECT_TRUE(std::isnan(lgamma_stirling_diff(nan))); |
| 16 | + EXPECT_FLOAT_EQ(lgamma_stirling_diff(inf), 0); |
| 17 | + EXPECT_THROW(std::isnan(lgamma_stirling_diff(-1.0)), std::domain_error); |
| 18 | + EXPECT_TRUE(std::isinf(lgamma_stirling_diff(0.0))); |
| 19 | + EXPECT_TRUE(lgamma_stirling_diff(0) > 0); |
| 20 | +} |
| 21 | + |
| 22 | +TEST(MathFunctions, lgamma_stirling_diff_accuracy) { |
| 23 | + using stan::math::lgamma_stirling_diff; |
| 24 | + using stan::math::lgamma_stirling_diff_useful; |
| 25 | + using stan::test::expect_near_rel; |
| 26 | + |
| 27 | + double start = std::nextafter(10, 11); |
| 28 | + for (double x = start; x < 1e8; x *= 1.5) { |
| 29 | + long double x_l = static_cast<long double>(x); |
| 30 | + long double stirling |
| 31 | + = 0.5 * std::log(2 * static_cast<long double>(stan::math::pi())) |
| 32 | + + (x_l - 0.5) * std::log(x_l) - x_l; |
| 33 | + long double lgamma_res = std::lgamma(x_l); |
| 34 | + double diff_actual = static_cast<double>(lgamma_res - stirling); |
| 35 | + double diff = lgamma_stirling_diff(x); |
| 36 | + |
| 37 | + std::ostringstream msg; |
| 38 | + msg << "x = " << x << "; lgamma = " << lgamma_res |
| 39 | + << "; stirling = " << stirling; |
| 40 | + expect_near_rel(msg.str(), diff, diff_actual, 1e-4); |
| 41 | + } |
| 42 | + |
| 43 | + double before_big = std::nextafter(lgamma_stirling_diff_useful, 0); |
| 44 | + double after_big = std::nextafter(lgamma_stirling_diff_useful, |
| 45 | + stan::math::positive_infinity()); |
| 46 | + expect_near_rel("big cutoff", lgamma_stirling_diff(before_big), |
| 47 | + lgamma_stirling_diff(after_big)); |
| 48 | +} |
| 49 | + |
| 50 | +namespace lgamma_stirling_diff_test_internal { |
| 51 | +struct TestValue { |
| 52 | + double x; |
| 53 | + double val; |
| 54 | +}; |
| 55 | + |
| 56 | +std::vector<TestValue> testValues = { |
| 57 | + {1.049787068367863943, 0.077388806767834476832}, |
| 58 | + {1.1353352832366126919, 0.071790358566585005482}, |
| 59 | + {1.3678794411714423216, 0.059960812482712981438}, |
| 60 | + {2., 0.041340695955409294094}, |
| 61 | + {3.7182818284590452354, 0.022358812123082674471}, |
| 62 | + {8.3890560989306502272, 0.0099288907523535997267}, |
| 63 | + {21.085536923187667741, 0.0039518599801395734578}, |
| 64 | + {55.598150033144239078, 0.0014988346688724404687}, |
| 65 | + {149.41315910257660342, 0.0005577367442531155476}, |
| 66 | + {404.42879349273512261, 0.00020605188772717995062}, |
| 67 | + {1097.6331584284585993, 0.000075920930766205666598}, |
| 68 | + {2981.9579870417282747, 0.00002794584410078046085}, |
| 69 | + {8104.0839275753840077, 0.000010282881326966996581}, |
| 70 | + {22027.465794806716517, 3.7831557249429676373e-6}, |
| 71 | + {59875.141715197818455, 1.3917851539949910276e-6}, |
| 72 | + {162755.79141900392081, 5.1201455018391551878e-7}, |
| 73 | + {442414.39200892050333, 1.8836035815859912686e-7}, |
| 74 | + {1.2026052841647767777e6, 6.9294002305342748064e-8}, |
| 75 | + {3.2690183724721106393e6, 2.5491852243801980915e-8}, |
| 76 | + {8.8861115205078726368e6, 9.3779301712579119232e-9}, |
| 77 | + {2.4154953753575298215e7, 3.4499479561619419703e-9}, |
| 78 | + {6.5659970137330511139e7, 1.2691649593966957356e-9}, |
| 79 | + {1.7848230196318726084e8, 4.6689970051216164913e-10}, |
| 80 | + {4.8516519640979027797e8, 1.7176280151585029843e-10}, |
| 81 | + {1.3188157354832146972e9, 6.3188003518019870566e-11}, |
| 82 | + {3.5849128471315915617e9, 2.3245567434090096532e-11}, |
| 83 | + {9.7448034472489026e9, 8.5515663588740238069e-12}, |
| 84 | + {2.6489122130843472294e10, 3.1459454534471511195e-12}, |
| 85 | + {7.2004899338385872524e10, 1.1573286553975954675e-12}, |
| 86 | + {1.9572960942983876427e11, 4.2575741900310182743e-13}, |
| 87 | + {5.3204824060279861668e11, 1.5662740137796255552e-13}, |
| 88 | + {1.4462570642924751737e12, 5.7620000891128517638e-14}, |
| 89 | +}; |
| 90 | + |
| 91 | +} // namespace lgamma_stirling_diff_test_internal |
| 92 | + |
| 93 | +TEST(MathFunctions, lgamma_stirling_diff_precomputed) { |
| 94 | + using stan::math::lgamma_stirling_diff; |
| 95 | + using stan::test::expect_near_rel; |
| 96 | + using lgamma_stirling_diff_test_internal::TestValue; |
| 97 | + using lgamma_stirling_diff_test_internal::testValues; |
| 98 | + |
| 99 | + for (TestValue t : testValues) { |
| 100 | + std::ostringstream msg; |
| 101 | + msg << "x = " << t.x; |
| 102 | + expect_near_rel(msg.str(), lgamma_stirling_diff(t.x), t.val, 1e-10); |
| 103 | + } |
| 104 | +} |
0 commit comments