| 1 |
/** |
|---|
| 2 |
Test consistency of all of the statistical functions which have inverses. |
|---|
| 3 |
These tests are really tough -- most will fail on machines which don't have |
|---|
| 4 |
80-bit reals. |
|---|
| 5 |
*/ |
|---|
| 6 |
module mathextra.testconsistency; |
|---|
| 7 |
|
|---|
| 8 |
import std.stdio; |
|---|
| 9 |
import mathextra.realtest; |
|---|
| 10 |
|
|---|
| 11 |
import mathextra.mathstat; |
|---|
| 12 |
import mathextra.mathspecial; |
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
version (testetcgamma) { |
|---|
| 16 |
import mathextra.etcgamma; |
|---|
| 17 |
alias mathextra.etcgamma.tgamma gamma; |
|---|
| 18 |
alias mathextra.etcgamma.lgamma loggamma; |
|---|
| 19 |
} else { |
|---|
| 20 |
import std.math; // for lgamma, tgamma |
|---|
| 21 |
alias std.math.tgamma gamma; |
|---|
| 22 |
alias std.math.lgamma loggamma; |
|---|
| 23 |
} |
|---|
| 24 |
|
|---|
| 25 |
import mathextra.complex; |
|---|
| 26 |
// do this just so it will compile. |
|---|
| 27 |
real cosh(real x) { return std.math.cosh(x); } |
|---|
| 28 |
real sinh(real x) { return std.math.sinh(x); } |
|---|
| 29 |
real sin(real x) { return std.math.sin(x); } |
|---|
| 30 |
real cos(real x) { return std.math.cos(x); } |
|---|
| 31 |
real exp(real x) { return std.math.exp(x); } |
|---|
| 32 |
real log(real x) { return std.math.log(x); } |
|---|
| 33 |
real acos(real x) { return std.math.acos(x); } |
|---|
| 34 |
real asin(real x) { return std.math.asin(x); } |
|---|
| 35 |
real atan(real x) { return std.math.atan(x); } |
|---|
| 36 |
|
|---|
| 37 |
// ------------------------------- |
|---|
| 38 |
// Tests of standard mathematical functions |
|---|
| 39 |
// ------------------------------- |
|---|
| 40 |
|
|---|
| 41 |
unittest { // lgamma and tgamma |
|---|
| 42 |
|
|---|
| 43 |
writefln("CONSISTENCY TESTS OF STANDARD FUNCTIONS"); |
|---|
| 44 |
|
|---|
| 45 |
static real logabsgamma(real x) |
|---|
| 46 |
{ |
|---|
| 47 |
// For poles, gamma(x) returns nan, but loggamma() returns infinity. |
|---|
| 48 |
if (x<0 && x==floor(x)) return real.infinity; |
|---|
| 49 |
return log(fabs(gamma(x))); |
|---|
| 50 |
} |
|---|
| 51 |
|
|---|
| 52 |
// Check that loggamma(x) = log(gamma(x)) provided x is not -1, -2, -3, ... |
|---|
| 53 |
|
|---|
| 54 |
// Test some high-precision values (50 decimal digits) |
|---|
| 55 |
const real SQRT_PI = 1.77245385090551602729816748334114518279754945612238L; |
|---|
| 56 |
assert(feqrel(gamma(0.5L), SQRT_PI) == real.mant_dig); |
|---|
| 57 |
|
|---|
| 58 |
// assert(consistencyTwoFuncs(&loggamma, &logabsgamma, -1000, 1700) > real.mant_dig-7); |
|---|
| 59 |
assert( |
|---|
| 60 |
consistencyTwoFuncs( |
|---|
| 61 |
(real x) { return exp(loggamma(x)); }, |
|---|
| 62 |
(real x) { if (x<0 && x==floor(x)) return real.infinity; |
|---|
| 63 |
return fabs(gamma(x)); }, |
|---|
| 64 |
-2000, real.infinity) |
|---|
| 65 |
> real.mant_dig-16); |
|---|
| 66 |
} |
|---|
| 67 |
|
|---|
| 68 |
// x*exp(x). Used only for testing |
|---|
| 69 |
real productExp(real x) |
|---|
| 70 |
{ |
|---|
| 71 |
return x*exp(x); |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
unittest { // productLog, productLog_1 |
|---|
| 75 |
assert(isNegZero(productLog(-0.0))); |
|---|
| 76 |
assert(isPosZero(productLog(0.0))); |
|---|
| 77 |
assert( consistencyRealInverse(&productLog, &productExp, |
|---|
| 78 |
-1/E, double.max) >= double.mant_dig); |
|---|
| 79 |
assert( consistencyRealInverse(&productExp, &productLog,-1, 11000) |
|---|
| 80 |
>= real.mant_dig-3); |
|---|
| 81 |
/+ |
|---|
| 82 |
assert( consistencyRealInverse(&productLog_1, &productExp, |
|---|
| 83 |
-1/E, -real.epsilon) >= double.mant_dig); |
|---|
| 84 |
assert( consistencyRealInverse(&productExp, &productLog_1, |
|---|
| 85 |
log(real.epsilon), -1) >= double.mant_dig); |
|---|
| 86 |
+/ |
|---|
| 87 |
} |
|---|
| 88 |
|
|---|
| 89 |
unittest { // cosh, acosh |
|---|
| 90 |
assert( consistencyRealUnity( (real x){ return cosh(acosh(x)); }, 1, double.max) |
|---|
| 91 |
>= double.mant_dig); |
|---|
| 92 |
assert( consistencyRealUnity( (real x){ return acosh(cosh(x)); }, 1, log(real.max)*(1-real.epsilon)) |
|---|
| 93 |
>= real.mant_dig-1); |
|---|
| 94 |
} |
|---|
| 95 |
|
|---|
| 96 |
unittest { // sinh, asinh |
|---|
| 97 |
assert( consistencyRealUnity((real x){ return sinh(asinh(x)); }, -double.max, double.max) >= double.mant_dig); |
|---|
| 98 |
assert( consistencyRealUnity((real x){ return sinh(asinh(x)); },-1, 1) >= real.mant_dig-2); |
|---|
| 99 |
assert( consistencyRealUnity((real x){ return asinh(sinh(x));}, |
|---|
| 100 |
-log(real.max)*(1+real.epsilon), log(real.max)*(1-real.epsilon) |
|---|
| 101 |
)>= double.mant_dig); |
|---|
| 102 |
} |
|---|
| 103 |
|
|---|
| 104 |
unittest { // tanh, atanh |
|---|
| 105 |
assert( consistencyRealInverse(&atanh, &tanh, -1, 1) |
|---|
| 106 |
>= real.mant_dig-2); |
|---|
| 107 |
assert( consistencyRealInverse(&tanh, &atanh, -1,1) |
|---|
| 108 |
>= real.mant_dig-2); |
|---|
| 109 |
} |
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
unittest { // tan, atan |
|---|
| 113 |
assert( consistencyRealInverse(&atan, &tan, -PI_2, PI_2) |
|---|
| 114 |
>= real.mant_dig-1); |
|---|
| 115 |
assert( consistencyRealInverse(&tan, &atan, -PI_2*(1-real.epsilon), PI_2*(1-real.epsilon)) |
|---|
| 116 |
>= real.mant_dig-2); |
|---|
| 117 |
} |
|---|
| 118 |
/+ |
|---|
| 119 |
// Sin and cos require absolute accuracy tests. |
|---|
| 120 |
|
|---|
| 121 |
unittest { // cos, acos |
|---|
| 122 |
writefln("cos"); |
|---|
| 123 |
//writefln(-PI_2, " ", cos(-PI_2), " ", acos(cos(PI_2*2))); |
|---|
| 124 |
writefln(-PI_2, " %a", cos(0x1p-63), " ", cos(acos(PI))); |
|---|
| 125 |
//writefln(-PI_2, " ", acos(-2), " ", acos(cos(-1))); |
|---|
| 126 |
assert( consistencyRealInverse(&acos, &cos, 0x1p-64, 1) |
|---|
| 127 |
>= real.mant_dig-1); |
|---|
| 128 |
|
|---|
| 129 |
/* |
|---|
| 130 |
assert( consistencyRealInverse(&cos, &acos, -PI_2*(1-real.epsilon), PI_2*(1-real.epsilon)) |
|---|
| 131 |
>= real.mant_dig-2); |
|---|
| 132 |
*/ |
|---|
| 133 |
} |
|---|
| 134 |
+/ |
|---|