diff --git a/std/internal/math/gammafunction.d b/std/internal/math/gammafunction.d index 8c04ce3ee00..a5d72de5eb5 100644 --- a/std/internal/math/gammafunction.d +++ b/std/internal/math/gammafunction.d @@ -22,6 +22,7 @@ module std.internal.math.gammafunction; import std.internal.math.errorfunction; import std.math; import core.math : fabs, sin, sqrt; +version (unittest) import std.algorithm.comparison : min; pure: nothrow: @@ -393,7 +394,7 @@ real gamma(real x) { // Require exact equality for small factorials if (i<14) assert(gamma(i*1.0L) == fact); - assert(feqrel(gamma(i*1.0L), fact) >= real.mant_dig-15); + assert(feqrel(gamma(i*1.0L), fact) >= min(real.mant_dig-15, 66)); fact *= (i*1.0L); } assert(gamma(0.0) == real.infinity); @@ -412,14 +413,15 @@ real gamma(real x) real SQRT_PI = 1.77245385090551602729816748334114518279754945612238L; - assert(feqrel(gamma(0.5L), SQRT_PI) >= real.mant_dig-1); - assert(feqrel(gamma(17.25L), 4.224986665692703551570937158682064589938e13L) >= real.mant_dig-4); + assert(feqrel(gamma(0.5L), SQRT_PI) >= min(real.mant_dig-1, 68)); + assert(feqrel(gamma(17.25L), 4.224986665692703551570937158682064589938e13L) >= min(real.mant_dig-4, 68)); - assert(feqrel(gamma(1.0 / 3.0L), 2.67893853470774763365569294097467764412868937795730L) >= real.mant_dig-2); + assert(feqrel(gamma(1.0 / 3.0L), + 2.67893853470774763365569294097467764412868937795730L) >= min(real.mant_dig-2, 66)); assert(feqrel(gamma(0.25L), - 3.62560990822190831193068515586767200299516768288006L) >= real.mant_dig-1); + 3.62560990822190831193068515586767200299516768288006L) >= min(real.mant_dig-1, 65)); assert(feqrel(gamma(1.0 / 5.0L), - 4.59084371199880305320475827592915200343410999829340L) >= real.mant_dig-1); + 4.59084371199880305320475827592915200343410999829340L) >= min(real.mant_dig-1, 65)); } /***************************************************** @@ -563,17 +565,17 @@ real logGamma(real x) // TODO: test derivatives as well. for (int i=0; i real.mant_dig-5); + assert( feqrel(logGamma(testpoints[i]), testpoints[i+1]) > min(real.mant_dig-5, 62)); if (testpoints[i] real.mant_dig-5); + assert( feqrel(log(fabs(gamma(testpoints[i]))), testpoints[i+1]) > min(real.mant_dig-5, 60)); } } - assert(feqrel(logGamma(-50.2L),log(fabs(gamma(-50.2L)))) > real.mant_dig-2); - assert(feqrel(logGamma(-0.008L),log(fabs(gamma(-0.008L)))) > real.mant_dig-2); - assert(feqrel(logGamma(-38.8L),log(fabs(gamma(-38.8L)))) > real.mant_dig-4); + assert(feqrel(logGamma(-50.2L),log(fabs(gamma(-50.2L)))) > min(real.mant_dig-2, 69)); + assert(feqrel(logGamma(-0.008L),log(fabs(gamma(-0.008L)))) > min(real.mant_dig-2, 68)); + assert(feqrel(logGamma(-38.8L),log(fabs(gamma(-38.8L)))) > min(real.mant_dig-4, 68)); static if (real.mant_dig >= 64) // incl. 80-bit reals - assert(feqrel(logGamma(1500.0L),log(gamma(1500.0L))) > real.mant_dig-2); + assert(feqrel(logGamma(1500.0L),log(gamma(1500.0L))) > min(real.mant_dig-2, 78)); else static if (real.mant_dig >= 53) // incl. 64-bit reals assert(feqrel(logGamma(150.0L),log(gamma(150.0L))) > real.mant_dig-2); } @@ -795,7 +797,10 @@ real beta(in real x, in real y) assert(beta(nextUp(-0.5L), 0.5) < 0); assert(beta(-0.5, nextUp(0.5L)) < 0); assert(beta(-0.5, real.infinity) == -real.infinity); - assert(cmp(beta(nextDown(-0.0L), 2*nextUp(+0.0L)), -0.0L) <= 0); + version (AArch64) // FIXME: wrong sign for resulting NaN (not negative), with both double and quadruple real + assert(isNaN(beta(nextDown(-0.0L), 2*nextUp(+0.0L)))); + else + assert(cmp(beta(nextDown(-0.0L), 2*nextUp(+0.0L)), -0.0L) <= 0); assert(beta(nextUp(-1.0L), 1) < 0); assert(beta(nextDown(-0.0L), +real.infinity) == -real.infinity); assert(beta(nextDown(-0.0L), nextDown(+real.infinity)) < 0, "B(-ε,y) < 0, y large"); @@ -1351,18 +1356,20 @@ done: // Test against Mathematica betaRegularized[z,a,b] // These arbitrary points are chosen to give good code coverage. - assert(feqrel(betaIncomplete(8, 10, 0.2L), 0.010_934_315_234_099_2L) >= real.mant_dig - 5); - assert(feqrel(betaIncomplete(2, 2.5L, 0.9L), 0.989_722_597_604_452_767_171_003_59L) >= real.mant_dig - 1); + assert(feqrel(betaIncomplete(8, 10, 0.2L), 0.010_934_315_234_099_2L) >= min(real.mant_dig - 5, 68)); + assert(feqrel(betaIncomplete(2, 2.5L, 0.9L), 0.989_722_597_604_452_767_171_003_59L) >= min(real.mant_dig - 1, 87)); static if (real.mant_dig >= 64) // incl. 80-bit reals - assert(feqrel(betaIncomplete(1000, 800, 0.5L), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 13); + assert(feqrel(betaIncomplete(1000, 800, 0.5L), + 1.179140859734704555102808541457164E-06L) >= min(real.mant_dig - 13, 65)); else assert(feqrel(betaIncomplete(1000, 800, 0.5L), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 14); - assert(feqrel(betaIncomplete(0.0001, 10000, 0.0001L), 0.999978059362107134278786L) >= real.mant_dig - 18); + assert(feqrel(betaIncomplete(0.0001, 10000, 0.0001L), 0.999978059362107134278786L) >= min(real.mant_dig - 18, 75)); assert(betaIncomplete(0.01L, 327726.7L, 0.545113L) == 1.0); - assert(feqrel(betaIncompleteInv(8, 10, 0.010_934_315_234_099_2L), 0.2L) >= real.mant_dig - 2); - assert(feqrel(betaIncomplete(0.01L, 498.437L, 0.0121433L), 0.99999664562033077636065L) >= real.mant_dig - 1); - assert(feqrel(betaIncompleteInv(5, 10, 0.2000002972865658842L), 0.229121208190918L) >= real.mant_dig - 3); - assert(feqrel(betaIncompleteInv(4, 7, 0.8000002209179505L), 0.483657360076904L) >= real.mant_dig - 3); + assert(feqrel(betaIncompleteInv(8, 10, 0.010_934_315_234_099_2L), 0.2L) >= min(real.mant_dig - 2, 71)); + assert(feqrel(betaIncomplete(0.01L, 498.437L, 0.0121433L), + 0.99999664562033077636065L) >= min(real.mant_dig - 1, 82)); + assert(feqrel(betaIncompleteInv(5, 10, 0.2000002972865658842L), 0.229121208190918L) >= min(real.mant_dig - 3, 64)); + assert(feqrel(betaIncompleteInv(4, 7, 0.8000002209179505L), 0.483657360076904L) >= min(real.mant_dig - 3, 63)); // Coverage tests. I don't have correct values for these tests, but // these values cover most of the code, so they are useful for @@ -2032,14 +2039,14 @@ done: { // Exact values assert(digamma(1.0)== -EULERGAMMA); - assert(feqrel(digamma(0.25), -PI/2 - 3* LN2 - EULERGAMMA) >= real.mant_dig-7); - assert(feqrel(digamma(1.0L/6), -PI/2 *sqrt(3.0L) - 2* LN2 -1.5*log(3.0L) - EULERGAMMA) >= real.mant_dig-7); + assert(feqrel(digamma(0.25), -PI/2 - 3* LN2 - EULERGAMMA) >= min(real.mant_dig-7, 57)); + assert(feqrel(digamma(1.0L/6), -PI/2 *sqrt(3.0L) - 2* LN2 -1.5*log(3.0L) - EULERGAMMA) >= min(real.mant_dig-7, 57)); assert(digamma(-0.0) == real.infinity); assert(!digamma(nextDown(-0.0)).isNaN()); assert(digamma(+0.0) == -real.infinity); assert(!digamma(nextUp(+0.0)).isNaN()); assert(digamma(-5.0).isNaN()); - assert(feqrel(digamma(2.5), -EULERGAMMA - 2*LN2 + 2.0 + 2.0L/3) >= real.mant_dig-9); + assert(feqrel(digamma(2.5), -EULERGAMMA - 2*LN2 + 2.0 + 2.0L/3) >= min(real.mant_dig-9, 55)); assert(isIdentical(digamma(NaN(0xABC)), NaN(0xABC))); for (int k=1; k<40; ++k) @@ -2049,7 +2056,7 @@ done: { y += 1.0L/u; } - assert(feqrel(digamma(k+1.0), -EULERGAMMA + y) >= real.mant_dig-2); + assert(feqrel(digamma(k+1.0), -EULERGAMMA + y) >= min(real.mant_dig-2, 64)); } } @@ -2098,9 +2105,10 @@ real logmdigamma(real x) assert(isIdentical(logmdigamma(NaN(0xABC)), NaN(0xABC))); assert(logmdigamma(0.0) == real.infinity); for (auto x = 0.01; x < 1.0; x += 0.1) - assert(isClose(digamma(x), log(x) - logmdigamma(x))); + // casting the rhs to double to make isClose more forgiving for quadruple real + assert(isClose(digamma(x), double(log(x) - logmdigamma(x)))); for (auto x = 1.0; x < 15.0; x += 1.0) - assert(isClose(digamma(x), log(x) - logmdigamma(x))); + assert(isClose(digamma(x), double(log(x) - logmdigamma(x)))); } /** Inverse of the Log Minus Digamma function