1 module rmathd.nf; 2 3 public import rmathd.common; 4 public import rmathd.nchisq; 5 public import rmathd.chisq; 6 public import rmathd.nbeta; 7 public import rmathd.gamma; 8 //import rmathd.normal; 9 10 11 /* 12 ** beta.d toms708.d 13 ** dmd nf.d common.d nchisq.d chisq.d nbeta.d gamma.d normal.d && ./nf 14 */ 15 16 17 T dnf(T: double)(T x, T df1, T df2, T ncp, int give_log) 18 { 19 T y, z, f; 20 21 mixin R_D__0!give_log; 22 if (isNaN(x) || isNaN(df1) || isNaN(df2) || isNaN(ncp)) 23 return x + df2 + df1 + ncp; 24 25 /* want to compare dnf(ncp=0) behavior with df() one, hence *NOT* : 26 * if (ncp == 0) 27 * return df(x, df1, df2, give_log); */ 28 29 if (df1 <= 0. || df2 <= 0. || ncp < 0) 30 return T.nan; 31 if (x < 0.) 32 return R_D__0; 33 if (!isFinite(ncp)) /* ncp = +Inf -- FIXME?: in some cases, limit exists */ 34 return T.nan; 35 36 /* This is not correct for df1 == 2, ncp > 0 - and seems unneeded: 37 * if (x == 0.) return(df1 > 2 ? R_D__0 : (df1 == 2 ? R_D__1 : ML_POSINF)); 38 */ 39 if (!isFinite(df1) && !isFinite(df2)) { /* both +Inf */ 40 /* PR: not sure about this (taken from ncp==0) -- FIXME ? */ 41 if(x == 1.) 42 return T.infinity; 43 else 44 return R_D__0; 45 } 46 if (!isFinite(df2)) /* i.e. = +Inf */ 47 return df1* dnchisq!T(x*df1, df1, ncp, give_log); 48 /* == dngamma(x, df1/2, 2./df1, ncp, give_log) -- but that does not exist */ 49 if (df1 > 1e14 && ncp < 1e7) { 50 /* includes df1 == +Inf: code below is inaccurate there */ 51 f = 1 + ncp/df1; /* assumes ncp << df1 [ignores 2*ncp^(1/2)/df1*x term] */ 52 z = dgamma(1./x/f, df2/2, 2./df2, give_log); 53 return give_log ? z - 2*log(x) - log(f) : z / (x*x) / f; 54 } 55 56 y = (df1 / df2) * x; 57 z = dnbeta!T(y/(1 + y), df1 / 2., df2 / 2., ncp, give_log); 58 return give_log ? 59 z + log(df1) - log(df2) - 2 * log1p(y) : 60 z * (df1 / df2) /(1 + y) / (1 + y); 61 } 62 63 64 T pnf(T: double)(T x, T df1, T df2, T ncp, int lower_tail, int log_p) 65 { 66 T y; 67 68 if (isNaN(x) || isNaN(df1) || isNaN(df2) || isNaN(ncp)) 69 return x + df2 + df1 + ncp; 70 71 if (df1 <= 0. || df2 <= 0. || ncp < 0) 72 return T.nan; 73 if (!isFinite(ncp)) 74 return T.nan; 75 if (!isFinite(df1) && !isFinite(df2)) /* both +Inf */ 76 return T.nan; 77 78 immutable(T) INF = T.infinity; 79 mixin R_P_bounds_01!(x, 0., INF); 80 81 if (df2 > 1e8) /* avoid problems with +Inf and loss of accuracy */ 82 return pnchisq!T(x * df1, df1, ncp, lower_tail, log_p); 83 84 y = (df1 / df2) * x; 85 return pnbeta2!T(y/(1. + y), 1./(1. + y), df1 / 2., df2 / 2., ncp, lower_tail, log_p); 86 } 87 88 T qnf(T: double)(T p, T df1, T df2, T ncp, int lower_tail, int log_p) 89 { 90 T y; 91 92 if (isNaN(p) || isNaN(df1) || isNaN(df2) || isNaN(ncp)) 93 return p + df1 + df2 + ncp; 94 95 if (df1 <= 0. || df2 <= 0. || ncp < 0) 96 return T.nan; 97 if (!isFinite(ncp)) 98 return T.nan; 99 if (!isFinite(df1) && !isFinite(df2)) 100 return T.nan; 101 immutable(T) INF = T.infinity; 102 mixin R_Q_P01_boundaries!(p, 0, INF); 103 104 if (df2 > 1e8) /* avoid problems with +Inf and loss of accuracy */ 105 return qnchisq!T(p, df1, ncp, lower_tail, log_p)/df1; 106 107 y = qnbeta!T(p, df1 / 2., df2 / 2., ncp, lower_tail, log_p); 108 return y/(1-y) * (df2/df1); 109 } 110 111 T rnf(T: double)(T df1, T df2, T ncp) 112 { 113 return (rnchisq!T(df1, ncp = ncp)/df1)/(rchisq!T(df2)/df2); 114 } 115 116 117 void test_nf() 118 { 119 import std.stdio: writeln; 120 writeln("dnf: ", dnf(7., 3., 4., 20., 0)); 121 writeln("pnf: ", pnf(7., 3., 4., 20., 1, 0)); 122 writeln("qnf: ", qnf(0.7, 3., 4., 20., 1, 0)); 123 writeln("rnf: ", rnf(3., 4., 20.), ", rnf: ", rnf(3., 4., 20.), ", rnf: ", rnf(3., 4., 20.)); 124 } 125 126