@@ -263,7 +263,19 @@ void test_spots(T, const char* name = nullptr)
263263 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(501.25 ), static_cast <T>(2000 )), static_cast <T>(-810 .2453406781655559126505101822969531699112391075198076300675402L ), tolerance);
264264 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(20 ), static_cast <T>(0.25 )), static_cast <T>(-2 .946458104491857816330873290969917497748067639461638294404e-31L ), tolerance);
265265 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(40 ), static_cast <T>(0.75 )), static_cast <T>(-5 .930604927955460343652485525435087275997461623988991819824e-54L ), tolerance);
266- #if defined(__CYGWIN__) || defined(__MINGW32__)
266+
267+ //
268+ // Check that lgamma_q returns correct values with spot values calculated via wolframalpha log(P[a, x])
269+ // This is calculated using: N[Log[GammaRegularized[a,0, z]],64]
270+ //
271+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(500 ), static_cast <T>(10 )), static_cast <T>(-1470 .017750815998931281954666549641187420649099004671023115157832L ), tolerance);
272+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(100 ), static_cast <T>(0.25 )), static_cast <T>(-502 .6163334118978895536207514636026023439623265152862757105793000L ), tolerance);
273+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(20 ), static_cast <T>(10.25 )), static_cast <T>(-5 .404004887981642339930593767572610169901594898478031307722239712L ), tolerance);
274+ // Small "a" produce larger errors
275+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(0.25 ), static_cast <T>(100 )), static_cast <T>(-3 .220751038854414755009496530271388459559061551701603447517040280e-46L ), tolerance);
276+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(0.25 ), static_cast <T>(10 )), static_cast <T>(-2 .083032578160285760530530498275075010777428544413918699832758176e-6L ), tolerance);
277+
278+ #if defined(__CYGWIN__) || defined(__MINGW32__)
267279 T gcc_win_mul = 2 ;
268280#else
269281 T gcc_win_mul = 1 ;
@@ -287,6 +299,24 @@ void test_spots(T, const char* name = nullptr)
287299 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(1200 ), static_cast <T>(1250.25 )), static_cast <T>(-2 .591934862117586205519309712218581885256650074210410262843591453L ), tolerance * ((std::numeric_limits<T>::max_digits10 >= 36 || std::is_same<T, boost::math::concepts::real_concept>::value) ? 750 : (std::is_same<T, float >::value ? 1 : 50 ))); // Test fails on ARM64 and s390x long doubles and real_concept types unless tolerance is adjusted
288300 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(2200 ), static_cast <T>(2249.75 )), static_cast <T>(-1 .933779894897391651410597618307863427927461116308937004149240320L ), tolerance * (std::is_floating_point<T>::value ? 1 : 10 ));
289301 BOOST_CHECK_CLOSE (::boost::math::lgamma_q (static_cast <T>(2200 ), static_cast <T>(2250.25 )), static_cast <T>(-1 .950346484067948344620463026377077515919992808640737320057812268L ), tolerance * (std::is_same<T, float >::value ? 1 : (std::is_floating_point<T>::value ? 100 : 200 )));
302+
303+ // Long double and real_concept types need increased precision
304+ T real_concept_tol = 1 ;
305+ if (std::is_same<T, boost::math::concepts::real_concept>::value || std::is_same<T, long double >::value){
306+ real_concept_tol = 3 ;
307+ }
308+ // Pair of tests that bisect the crossover condition in our code at double and then quad precision
309+ // Oddly, the crossover condition is smaller for quad precision. This is because max_factorial is 100
310+ // for boost::multiprecision::cpp_bin_float_quad and 170 for doubles.
311+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(169.75 ), static_cast <T>(0.75 )), static_cast <T>(-754 .8681912874632573100058312311927462406154378562940316233389406L ), tolerance * real_concept_tol);
312+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(170.25 ), static_cast <T>(0.75 )), static_cast <T>(-757 .5814133895304434271729579978676692688834086380018151200693572L ), tolerance * real_concept_tol);
313+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(99.75 ), static_cast <T>(0.75 )), static_cast <T>(-392 .0259615581237826290999388631292473247947826682978959914359465L ), tolerance * real_concept_tol);
314+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(100.25 ), static_cast <T>(0.75 )), static_cast <T>(-394 .4749200332583219473980963811639065003421270272773619742710832L ), tolerance * real_concept_tol);
315+
316+ // Check large a, x values. Precision just isn't great here.
317+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(1450.25 ), static_cast <T>(1500.75 )), static_cast <T>(-0 .09812447528127799786140178403478691390753413399549580160096975713L ), tolerance * (std::is_same<T, boost::math::concepts::real_concept>::value ? 16 : 1 ));
318+ BOOST_CHECK_CLOSE (::boost::math::lgamma_p (static_cast <T>(2000 ), static_cast <T>(1900 )), static_cast <T>(-4 .448523733381445722945397105917814000790587922314824687065050805L ), tolerance * gcc_win_mul * (std::is_same<T, boost::math::concepts::real_concept>::value ? 8 : 1 ));
319+
290320 //
291321 // Coverage:
292322 //
@@ -302,6 +332,10 @@ void test_spots(T, const char* name = nullptr)
302332 BOOST_CHECK_THROW (boost::math::lgamma_q (static_cast <T>(1 ), static_cast <T>(-2 )), std::domain_error);
303333 BOOST_CHECK_THROW (boost::math::lgamma_q (static_cast <T>(0 ), static_cast <T>(2 )), std::domain_error);
304334
335+ BOOST_CHECK_THROW (boost::math::lgamma_p (static_cast <T>(-1 ), static_cast <T>(2 )), std::domain_error);
336+ BOOST_CHECK_THROW (boost::math::lgamma_p (static_cast <T>(1 ), static_cast <T>(-2 )), std::domain_error);
337+ BOOST_CHECK_THROW (boost::math::lgamma_p (static_cast <T>(0 ), static_cast <T>(2 )), std::domain_error);
338+
305339 BOOST_CHECK_THROW (boost::math::gamma_p_derivative (static_cast <T>(-1 ), static_cast <T>(2 )), std::domain_error);
306340 BOOST_CHECK_THROW (boost::math::gamma_p_derivative (static_cast <T>(1 ), static_cast <T>(-2 )), std::domain_error);
307341 BOOST_CHECK_THROW (boost::math::gamma_p_derivative (static_cast <T>(0 ), static_cast <T>(2 )), std::domain_error);
@@ -317,6 +351,10 @@ void test_spots(T, const char* name = nullptr)
317351 BOOST_CHECK ((boost::math::isnan)(boost::math::lgamma_q (static_cast <T>(1 ), static_cast <T>(-2 ))));
318352 BOOST_CHECK ((boost::math::isnan)(boost::math::lgamma_q (static_cast <T>(0 ), static_cast <T>(2 ))));
319353
354+ BOOST_CHECK ((boost::math::isnan)(boost::math::lgamma_p (static_cast <T>(-1 ), static_cast <T>(2 ))));
355+ BOOST_CHECK ((boost::math::isnan)(boost::math::lgamma_p (static_cast <T>(1 ), static_cast <T>(-2 ))));
356+ BOOST_CHECK ((boost::math::isnan)(boost::math::lgamma_p (static_cast <T>(0 ), static_cast <T>(2 ))));
357+
320358 BOOST_CHECK ((boost::math::isnan)(boost::math::gamma_p_derivative (static_cast <T>(-1 ), static_cast <T>(2 ))));
321359 BOOST_CHECK ((boost::math::isnan)(boost::math::gamma_p_derivative (static_cast <T>(1 ), static_cast <T>(-2 ))));
322360 BOOST_CHECK ((boost::math::isnan)(boost::math::gamma_p_derivative (static_cast <T>(0 ), static_cast <T>(2 ))));
0 commit comments