PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/assessment/libs/stats.php

https://github.com/xiongchiamiov/IMathAS
PHP | 1167 lines | 1062 code | 26 blank | 79 comment | 101 complexity | 74142c2570cde5ff78db7ddd3464c9e4 MD5 | raw file
  1. <?php
  2. //A library of Stats functions. Version 1.9, March 30, 2008
  3. global $allowedmacros;
  4. array_push($allowedmacros,"nCr","nPr","mean","stdev","percentile","quartile","TIquartile","median","freqdist","frequency","histogram","fdhistogram","fdbargraph","normrand","boxplot","normalcdf","tcdf","invnormalcdf","invtcdf","invtcdf2","linreg","countif","binomialpdf","binomialcdf","chicdf","invchicdf","chi2cdf","invchi2cdf","fcdf","invfcdf","piechart");
  5. //nCr(n,r)
  6. //The Choose function
  7. function nCr($n,$r){
  8. if ($r > $n)
  9. return false;
  10. if (($n-$r) < $r)
  11. return nCr($n,($n-$r));
  12. $return = 1;
  13. for ($i=0;$i < $r;$i++){
  14. $return *= ($n-$i)/($i+1);
  15. }
  16. return $return;
  17. }
  18. //nPr(n,r)
  19. //The Permutations function
  20. function nPr($n,$r){
  21. if ($r > $n)
  22. return false;
  23. if ($r==0)
  24. return 1;
  25. $return = 1;
  26. $i = $n-$r;
  27. while ($i<$n) {
  28. $return *= ++$i;
  29. }
  30. return $return;
  31. }
  32. //mean(array)
  33. //Finds the mean of an array of numbers
  34. function mean($a) {
  35. return (array_sum($a)/count($a));
  36. }
  37. //variance(array)
  38. //the (sample) variance of an array of numbers
  39. function variance($a) {
  40. $v = 0;
  41. $mean = mean($a);
  42. foreach ($a as $x) {
  43. $v += pow($x-$mean,2);
  44. }
  45. return ($v/(count($a)-1));
  46. }
  47. //stdev(array)
  48. //the (sample) standard deviation of an array of numbers
  49. function stdev($a) {
  50. return sqrt(variance($a));
  51. }
  52. //percentile(array,percentile)
  53. //example: percentile($a,30) would find the 30th percentile of the data
  54. //method based on Triola
  55. function percentile($a,$p) {
  56. sort($a, SORT_NUMERIC);
  57. if ($p==0) {
  58. return $a[0];
  59. } else if ($p==100) {
  60. return $a[count($a)-1];
  61. }
  62. $l = $p*count($a)/100;
  63. if (floor($l)==$l) {
  64. return (($a[$l-1]+$a[$l])/2);
  65. } else {
  66. return ($a[ceil($l)-1]);
  67. }
  68. }
  69. //quartile(array,quartile)
  70. //finds the 0 (min), 1st, 2nd (median), 3rd, or 4th (max) quartile of an
  71. //array of numbers. Calculates using percentiles.
  72. function quartile($a,$q) {
  73. return percentile($a,$q*25);
  74. }
  75. //TIquartile(array,quartile)
  76. //finds the 0 (min), 1st, 2nd (median), 3rd, or 4th (max) quartile of an
  77. //array of numbers. Calculates using the TI-84 method.
  78. function TIquartile($a,$q) {
  79. sort($a, SORT_NUMERIC);
  80. $n = count($a);
  81. if ($q==0) {
  82. return $a[0];
  83. } else if ($q==4) {
  84. return $a[count($a)-1];
  85. }
  86. if ($q==2) {
  87. if ($n%2==0) { //even
  88. $m = $n/2;
  89. return (($a[$m-1] + $a[$m])/2);
  90. } else {
  91. return ($a[floor($n/2)]);
  92. }
  93. } else {
  94. if ($n%2==0) { //even
  95. if ($n%4==0) { //lower half is even
  96. $m = $n/4;
  97. if ($q==3) { $m = $n-$m;}
  98. return (($a[$m-1] + $a[$m])/2);
  99. } else {
  100. $m = floor($n/4);
  101. if ($q==3) { $m = $n-$m-1;}
  102. return ($a[$m]);
  103. }
  104. } else {
  105. if ((($n-1)/2)%2==0) {//lower half is even
  106. $m = floor($n/4);
  107. if ($q==3) { $m = $n-$m;}
  108. return (($a[$m-1] + $a[$m])/2);
  109. } else {
  110. $m = floor($n/4);
  111. if ($q==3) { $m = $n-$m-1;}
  112. return ($a[$m]);
  113. }
  114. }
  115. }
  116. }
  117. //median(array)
  118. //returns the median of an array of numbers
  119. function median($a) {
  120. return percentile($a,50);
  121. }
  122. //freqdist(array,label,start,classwidth)
  123. //display macro. Returns an HTML table that is a frequency distribution of
  124. //the data
  125. // array: array of data values
  126. // label: name of data values
  127. // start: first lower class limit
  128. // classwidth: width of the classes
  129. function freqdist($a,$label,$start,$cw) {
  130. if ($cw<0) { $cw *= -1;} else if ($cw==0) { echo "Error - classwidth cannot be 0"; return 0;}
  131. sort($a, SORT_NUMERIC);
  132. $x = $start;
  133. $curr = 0;
  134. $out = "<table class=stats><thead><tr><th>$label</th><th>Freq</th></tr></thead>\n<tbody>\n";
  135. while ($x <= $a[count($a)-1]) {
  136. $out .= "<tr><td>`$x <= x < ";
  137. $x += $cw;
  138. $out .= "$x`</td><td>";
  139. $i = $curr;
  140. while (($a[$i] < $x) && ($i < count($a))) {
  141. $i++;
  142. }
  143. $out .= ($i-$curr) . "</td></tr>\n";
  144. $curr = $i;
  145. }
  146. $out .= "</tbody></table>\n";
  147. return $out;
  148. }
  149. //frequency(array,start,classwidth)
  150. //Returns an array of frequencies for the data grouped into classes
  151. // array: array of data values
  152. // start: first lower class limit
  153. // classwidth: width of the classes
  154. function frequency($a,$start,$cw) {
  155. if ($cw<0) { $cw *= -1;} else if ($cw==0) { echo "Error - classwidth cannot be 0"; return 0;}
  156. sort($a, SORT_NUMERIC);
  157. $x = $start;
  158. $curr = 0;
  159. while ($x <= $a[count($a)-1]) {
  160. $x += $cw;
  161. $i = $curr;
  162. while (($a[$i] < $x) && ($i < count($a))) {
  163. $i++;
  164. }
  165. $out[] = ($i-$curr);
  166. $curr = $i;
  167. }
  168. return $out;
  169. }
  170. //countif(array,condition)
  171. //Returns count of items in array that meet condition
  172. // array: array of data values
  173. // condition: a condition, using x for data values
  174. //Example: countif($a,"x<3 && x>2")
  175. function countif($a,$ifcond) {
  176. $rsnoquote = preg_replace('/"[^"]*"/','""',$ifcond);
  177. $rsnoquote = preg_replace('/\'[^\']*\'/','\'\'',$rsnoquote);
  178. if (preg_match_all('/([$\w]+)\s*\([^\)]*\)/',$rsnoquote,$funcs)) {
  179. $ismath = true;
  180. for ($i=0;$i<count($funcs[1]);$i++) {
  181. if (strpos($funcs[1][$i],"$")===false) {
  182. if (!in_array($funcs[1][$i],$allowedmacros)) {
  183. echo "{$funcs[1][$i]} is not an allowed function<BR>\n";
  184. return false;
  185. }
  186. }
  187. }
  188. }
  189. $ifcond = str_replace('!=','#=',$ifcond);
  190. $ifcond = mathphp($ifcond,'x');
  191. $ifcond = str_replace('#=','!=',$ifcond);
  192. $ifcond = str_replace('(x)','($x)',$ifcond);
  193. $iffunc = create_function('$x','return('.$ifcond.');');
  194. $cnt = 0;
  195. foreach ($a as $v) {
  196. if ($iffunc($v)) {
  197. $cnt++;
  198. }
  199. }
  200. return $cnt;
  201. }
  202. //histogram(array,label,start,classwidth,[labelstart,upper,width,height])
  203. //display macro. Creates a histogram from a data set
  204. // array: array of data values
  205. // label: name of data values
  206. // start: first lower class limit
  207. // classwidth: width of the classes
  208. // labelstart (optional): value to start axis labeling at. Defaults to start
  209. // upper (optional): first upper class limit. Defaults to start+classwidth
  210. // width,height (optional): width and height in pixels of graph
  211. function histogram($a,$label,$start,$cw,$startlabel=false,$upper=false,$width=300,$height=200) {
  212. if ($cw<0) { $cw *= -1;} else if ($cw==0) { echo "Error - classwidth cannot be 0"; return 0;}
  213. sort($a, SORT_NUMERIC);
  214. $x = $start;
  215. $curr = 0;
  216. $alt = "Histogram for $label <table class=stats><thead><tr><th>Label on left of box</th><th>Frequency</th></tr></thead>\n<tbody>\n";
  217. $maxfreq = 0;
  218. if ($upper===false) {
  219. $dx = $cw;
  220. $dxdiff = 0;
  221. } else {
  222. $dx = $upper - $start;
  223. $dxdiff = $cw-$dx;
  224. }
  225. while ($x <= $a[count($a)-1]) {
  226. $alt .= "<tr><td>$x</td>";
  227. $st .= "rect([$x,0],";
  228. $x += $dx;
  229. $st .= "[$x,";
  230. $i = $curr;
  231. while (($a[$i] < $x) && ($i < count($a))) {
  232. $i++;
  233. }
  234. if (($i-$curr)>$maxfreq) { $maxfreq = $i-$curr;}
  235. $alt .= "<td>" . ($i-$curr) . "</td></tr>\n";
  236. $st .= ($i-$curr) . "]);";
  237. $curr = $i;
  238. $x += $dxdiff;
  239. }
  240. $alt .= "</tbody></table>\n";
  241. if ($GLOBALS['sessiondata']['graphdisp']==0) {
  242. return $alt;
  243. }
  244. $outst = "setBorder(".(40+7*strlen($maxfreq)).",40,10,5); initPicture(".($start>0?(max($start-.9*$cw,0)):$start).",$x,0,$maxfreq);";
  245. $power = floor(log10($maxfreq))-1;
  246. $base = $maxfreq/pow(10,$power);
  247. if ($base>75) {$step = 20*pow(10,$power);} else if ($base>40) { $step = 10*pow(10,$power);} else if ($base>20) {$step = 5*pow(10,$power);} else if ($base>9) {$step = 2*pow(10,$power);} else {$step = pow(10,$power);}
  248. //if ($maxfreq>100) {$step = 20;} else if ($maxfreq > 50) { $step = 10; } else if ($maxfreq > 20) { $step = 5;} else if ($maxfreq>9) { $step = 2; } else {$step=1;}
  249. if ($startlabel===false) {
  250. //$outst .= "axes($cw,$step,1,1000,$step); fill=\"blue\"; textabs([". ($width/2+15) .",0],\"$label\",\"above\");";
  251. $startlabel = $start;
  252. } //else {
  253. $outst .= "axes(1000,$step,1,1000,$step); fill=\"blue\"; textabs([". ($width/2+15) .",0],\"$label\",\"above\");";
  254. $x = $startlabel;
  255. $tm = -.02*$maxfreq;
  256. $tx = .02*$maxfreq;
  257. while ($x <= $a[count($a)-1]+1) {
  258. $outst .= "line([$x,$tm],[$x,$tx]); text([$x,0],\"$x\",\"below\");";
  259. $x+= $cw;
  260. }
  261. //}
  262. $outst .= "textabs([0,". ($height/2+15) ."],\"Frequency\",\"right\",90);";
  263. $outst .= $st;
  264. return showasciisvg($outst,$width,$height);
  265. }
  266. //fdhistogram(freqarray,label,start,cw,[labelstart,upper,width,height])
  267. //display macro. Creates a histogram from frequency array
  268. // freqarray: array of frequencies
  269. // label: name of data values
  270. // start: first lower class limit
  271. // classwidth: width of the classes
  272. // labelstart (optional): value to start axis labeling at. Defaults to start
  273. // upper (optional): first upper class limit. Defaults to start+classwidth
  274. // width,height (optional): width and height in pixels of graph
  275. function fdhistogram($freq,$label,$start,$cw,$startlabel=false,$upper=false,$width=300,$height=200) {
  276. if ($cw<0) { $cw *= -1;} else if ($cw==0) { echo "Error - classwidth cannot be 0"; return 0;}
  277. $x = $start;
  278. $alt = "Histogram for $label <table class=stats><thead><tr><th>Label on left of box</th><th>Frequency</th></tr></thead>\n<tbody>\n";
  279. $maxfreq = 0;
  280. if ($upper===false) {
  281. $dx = $cw;
  282. $dxdiff = 0;
  283. } else {
  284. $dx = $upper - $start;
  285. $dxdiff = $cw-$dx;
  286. }
  287. for ($curr=0; $curr<count($freq); $curr++) {
  288. $alt .= "<tr><td>$x</td><td>{$freq[$curr]}</td></tr>";
  289. $st .= "rect([$x,0],";
  290. $x += $dx;
  291. $st .= "[$x,{$freq[$curr]}]);";
  292. if ($freq[$curr]>$maxfreq) { $maxfreq = $freq[$curr];}
  293. $x += $dxdiff;
  294. }
  295. $alt .= "</tbody></table>\n";
  296. if ($GLOBALS['sessiondata']['graphdisp']==0) {
  297. return $alt;
  298. }
  299. $outst = "setBorder(".(40+7*strlen($maxfreq)).",40,10,5); initPicture(".($start>0?(max($start-.9*$cw,0)):$start).",$x,0,$maxfreq);";
  300. //$outst = "setBorder(10); initPicture(". ($start-.1*($x-$start)) .",$x,". (-.1*$maxfreq) .",$maxfreq);";
  301. $power = floor(log10($maxfreq))-1;
  302. $base = $maxfreq/pow(10,$power);
  303. if ($base>75) {$step = 20*pow(10,$power);} else if ($base>40) { $step = 10*pow(10,$power);} else if ($base>20) {$step = 5*pow(10,$power);} else if ($base>9) {$step = 2*pow(10,$power);} else {$step = pow(10,$power);}
  304. //if ($maxfreq>100) {$step = 20;} else if ($maxfreq > 50) { $step = 10; } else if ($maxfreq > 20) { $step = 5;} else if ($maxfreq>9) {$step = 2;} else {$step=1;}
  305. if ($startlabel===false) {
  306. //$outst .= "axes($cw,$step,1,1000,$step); fill=\"blue\"; textabs([". ($width/2+15) .",0],\"$label\",\"above\");";
  307. $startlabel = $start;
  308. } //else {
  309. $outst .= "axes(1000,$step,1,1000,$step); fill=\"blue\"; textabs([". ($width/2+15) .",0],\"$label\",\"above\");";
  310. $x = $startlabel;
  311. $tm = -.02*$maxfreq;
  312. $tx = .02*$maxfreq;
  313. for ($curr=0; $curr<count($freq)+1; $curr++) {
  314. $outst .= "line([$x,$tm],[$x,$tx]); text([$x,0],\"$x\",\"below\");";
  315. $x+=$cw;
  316. }
  317. //}
  318. //$outst .= "text([".($start-.1*($x-$start)).",".(.5*$maxfreq)."],\"Freq\",,90)";
  319. //$outst .= "axes($cw,$step,1,1000,$step); fill=\"blue\"; text([". ($start + .5*($x-$start)) .",". (-.1*$maxfreq) . "],\"$label\");";
  320. $outst .= "textabs([0,". ($height/2+15) ."],\"Frequency\",\"right\",90);";
  321. $outst .= $st;
  322. return showasciisvg($outst,$width,$height);
  323. }
  324. //fdbargraph(barlabels,freqarray,label,[width,height])
  325. //barlabels: array of labels for the bars
  326. //freqarray: array of frequencies/heights for the bars
  327. //label: general label for bars
  328. //width,height (optional): width and height for graph
  329. function fdbargraph($bl,$freq,$label,$width=300,$height=200) {
  330. if (!is_array($bl) || !is_array($freq)) {echo "barlabels and freqarray must be arrays"; return 0;}
  331. if (count($bl) != count($freq)) { echo "barlabels and freqarray must have same length"; return 0;}
  332. $alt = "Histogram for $label <table class=stats><thead><tr><th>Bar Label</th><th>Frequency/Height</th></tr></thead>\n<tbody>\n";
  333. $start = 0;
  334. $x = $start+1;
  335. $maxfreq = 0;
  336. for ($curr=0; $curr<count($bl); $curr++) {
  337. $alt .= "<tr><td>{$bl[$curr]}</td><td>{$freq[$curr]}</td></tr>";
  338. $st .= "rect([$x,0],";
  339. $x += 2;
  340. $st .= "[$x,{$freq[$curr]}]);";
  341. $x -= 1;
  342. $st .= "text([$x,0],\"{$bl[$curr]}\",\"below\");";
  343. $x += 1;
  344. if ($freq[$curr]>$maxfreq) { $maxfreq = $freq[$curr];}
  345. }
  346. $alt .= "</tbody></table>\n";
  347. if ($GLOBALS['sessiondata']['graphdisp']==0) {
  348. return $alt;
  349. }
  350. $x++;
  351. //$outst = "setBorder(10); initPicture(". ($start-.1*($x-$start)) .",$x,". (-.1*$maxfreq) .",$maxfreq);";
  352. $outst = "setBorder(45,40,10,5); initPicture(".($start>0?(max($start-.9*$cw,0)):$start).",$x,0,$maxfreq);";
  353. $power = floor(log10($maxfreq))-1;
  354. $base = $maxfreq/pow(10,$power);
  355. if ($base>75) {$step = 20*pow(10,$power);} else if ($base>40) { $step = 10*pow(10,$power);} else if ($base>20) {$step = 5*pow(10,$power);} else if ($base>9) {$step = 2*pow(10,$power);} else {$step = pow(10,$power);}
  356. //if ($maxfreq>100) {$step = 20;} else if ($maxfreq > 50) { $step = 10; } else if ($maxfreq > 20) { $step = 5;} else {$step=1;}
  357. $outst .= "axes(1000,$step,1,1000,$step); fill=\"blue\"; textabs([". ($width/2+15) .",0],\"$label\",\"above\");";
  358. //$outst .= "axes($cw,$step,1,1000,$step); fill=\"blue\"; text([". ($start + .5*($x-$start)) .",". (-.1*$maxfreq) . "],\"$label\");";
  359. $outst .= $st;
  360. return showasciisvg($outst,$width,$height);
  361. }
  362. //piechart(percents, labels, {width, height})
  363. //create a piechart
  364. //percents: array of pie percents (should total 100%)
  365. //labels: array of labels for each pie piece
  366. //uses Google Charts API
  367. function piechart($pcts,$labels,$w=350,$h=150) {
  368. $out = "<img src=\"http://chart.apis.google.com/chart?cht=p&amp;chd=t:";
  369. $out .= implode(',',$pcts);
  370. $out .= "&amp;chs={$w}x{$h}&amp;chl=";
  371. $out .= implode('|',$labels);
  372. $out .= '" alt="Pie Chart" />';
  373. return $out;
  374. }
  375. //normrand(mu,sigma,n)
  376. //returns an array of n random numbers that are normally distributed with given
  377. //mean mu and standard deviation sigma. Uses the Box-Muller transform.
  378. function normrand($mu,$sig,$n) {
  379. for ($i=0;$i<ceil($n/2);$i++) {
  380. do {
  381. $a = rand(-32768,32768)/32768;
  382. $b = rand(-32768,32768)/32768;
  383. $r = $a*$a+$b*$b;
  384. $count++;
  385. } while ($r==0||$r>1);
  386. $r = sqrt(-2*log($r)/$r);
  387. $z[] = $sig*$a*$r + $mu;
  388. $z[] = $sig*$b*$r + $mu;
  389. }
  390. if ($n%2==0) {
  391. return $z;
  392. } else {
  393. return (array_slice($z,0,count($z)-1));
  394. }
  395. }
  396. //boxplot(array,axislabel,[datalabel])
  397. //draws a boxplot based on the data in array, with given axislabel
  398. //and optionally a datalabel (to topleft of boxplot)
  399. //array and datalabel can also be an array of dataarrays and
  400. //array of datalabels to do comparative boxplots
  401. function boxplot($arr,$label) {
  402. if (func_num_args()>2) {
  403. $dlbls = func_get_arg(2);
  404. }
  405. if (is_array($arr[0])) { $multi = count($arr);} else {$multi = 1;}
  406. $st = '';
  407. $bigmax = -10000000;
  408. $bigmin = 100000000;
  409. $alt = "Boxplot, axis label: $label. ";
  410. for ($i=0;$i<$multi;$i++) {
  411. if ($multi==1) { $a = $arr;} else {$a = $arr[$i];}
  412. sort($a,SORT_NUMERIC);
  413. $max = $a[count($a)-1];
  414. if ($max>$bigmax) { $bigmax = $max;}
  415. if ($a[0]<$bigmin) {$bigmin = $a[0];}
  416. $q1 = percentile($a,25);
  417. $q2 = percentile($a,50);
  418. $q3 = percentile($a,75);
  419. $yl = 2+5*$i;
  420. $ym = $yl+1;
  421. $yh = $ym+1;
  422. $st .= "line([$a[0],$yl],[$a[0],$yh]); rect([$q1,$yl],[$q3,$yh]); line([$q2,$yl],[$q2,$yh]);";
  423. $st .= "line([$max,$yl],[$max,$yh]); line([$a[0],$ym],[$q1,$ym]); line([$q3,$ym],[$max,$ym]);";
  424. $alt .= 'Boxplot ';
  425. if (isset($dlbls[$i])) {
  426. $alt .= "for {$dlbls[$i]}";
  427. } else {
  428. $alt .= ($i+1);
  429. }
  430. $alt .= ": Left whisker at {$a[0]}. Leftside of box at $q1. Line through box at $q2. Rightside of box at $q3. Right whisker at $max.\n";
  431. }
  432. if ($GLOBALS['sessiondata']['graphdisp']==0) {
  433. return $alt;
  434. }
  435. $outst = "setBorder(15); initPicture($bigmin,$bigmax,-3,".(5*$multi).");";
  436. $dw = $bigmax-$bigmin;
  437. if ($dw>100) {$step = 20;} else if ($dw > 50) { $step = 10; } else if ($dw > 20) { $step = 5;} else {$step=1;}
  438. $outst .= "axes($step,100,1,0,0,1,'off');";
  439. $outst .= "text([". ($bigmin+.5*$dw) . ",-3],\"$label\");";
  440. if (isset($dlbls)) {
  441. for ($i=0;$i<$multi;$i++) {
  442. if ($multi>1) { $dlbl = $dlbls[$i];} else {$dlbl = $dlbls;}
  443. $st .= "text([$bigmin,". (5+5*$i) ."],\"$dlbl\",\"right\");";
  444. }
  445. }
  446. $outst .= $st;
  447. return showasciisvg($outst,400,50+50*$multi);
  448. }
  449. //normalcdf(z,[dec])
  450. //calculates the area under the standard normal distribution to the left of the
  451. //z-value z, to dec decimals (defaults to 4)
  452. //based on someone else's code - can't remember whose!
  453. function normalcdf($ztest,$dec=4) {
  454. $eps = pow(.1,$dec);
  455. $eps2 = pow(.1,$dec+3);
  456. $ds = 1;
  457. $s = 0;
  458. $i = 0;
  459. $z = abs($ztest);
  460. $fact = 1;
  461. while (abs($ds)>$eps2) {
  462. $ds = pow(-1,$i)*pow($z,2.0*$i+1.0)/(pow(2.0,$i)*$fact*(2.0*$i+1.0));
  463. $s += $ds;
  464. $i++;
  465. $fact *= $i;
  466. if (abs($s)<$eps) {
  467. break;
  468. }
  469. }
  470. /* alternate code, less accuracy; around 10^-8 vs 10^-10 w above
  471. $b1 = 0.319381530;
  472. $b2 = -0.356563782;
  473. $b3 = 1.781477937;
  474. $b4 = -1.821255978;
  475. $b5 = 1.330274429;
  476. $p = 0.2316419;
  477. $c = 0.39894228;
  478. $x = $ztest;
  479. if($x >= 0.0) {
  480. $t = 1.0 / ( 1.0 + $p * $x );
  481. return (1.0 - $c * exp( -$x * $x / 2.0 ) * $t *
  482. ( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
  483. }
  484. else {
  485. $t = 1.0 / ( 1.0 - $p * $x );
  486. return ( $c * exp( -$x * $x / 2.0 ) * $t *
  487. ( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
  488. }
  489. */
  490. $s *= 0.3989422804;
  491. $s = round($s,$dec);
  492. if ($ztest > 0) {
  493. $pval = .5 + $s;
  494. } else {
  495. $pval = .5 - $s;
  496. }
  497. if ($pval < $eps) {
  498. $pval = $eps;
  499. } else if ($pval > (1-$eps)) {
  500. $pval = round(1-$eps,$dec);
  501. }
  502. return $pval;
  503. }
  504. //tcdf(t,df,[dec])
  505. //calculates the area under the t-distribution with "df" degrees of freedom
  506. //to the left of the t-value t
  507. //based on someone else's code - can't remember whose!
  508. function tcdf($ttest,$df,$dec=4) {
  509. $eps = pow(.1,$dec);
  510. $t = abs($ttest);
  511. if ($df > 0) {
  512. $k3 = 0;
  513. $c3 = 0;
  514. $a3 = $t/sqrt($df);
  515. $b3 = 1+pow($a3,2);
  516. $y = 0.5;
  517. if (abs(floor($df/2)*2 - $df) < $eps) {
  518. $c3 = $a3/(2*pow($b3,0.5));
  519. $k3 = 0;
  520. } else {
  521. $c3 = $a3/($b3*M_PI);
  522. $y += atan($a3)/M_PI;
  523. $k3 = 1;
  524. }
  525. if ($df > 1) {
  526. $k3 += 2;
  527. $y += $c3;
  528. $c3 *= ($k3-1)/($k3*$b3);
  529. while ($k3 < $df) {
  530. $k3 += 2;
  531. $y += $c3;
  532. $c3 *= ($k3-1)/($k3*$b3);
  533. }
  534. }
  535. if ($ttest > 0) {
  536. $pval = round($y,$dec);
  537. } else {
  538. $pval = round(1-$y,$dec);
  539. }
  540. if ($pval > (1-$eps)) {
  541. $pval = round(1-$eps,$dec);
  542. } else if ($pval < $eps) {
  543. $pval = $eps;
  544. }
  545. return $pval;
  546. } else {return false;}
  547. }
  548. //invnormalcdf(p,[dec])
  549. //Inverse Normal CDF
  550. //finds the z-value with a left-tail area of p, to dec decimals (default 5)
  551. // from Odeh & Evans. 1974. AS 70. Applied Statistics. 23: 96-97
  552. function invnormalcdf($p,$dec=5) {
  553. $p0 = -0.322232431088;
  554. $p1 = -1.0;
  555. $p2 = -0.342242088547;
  556. $p3 = -0.0204231210245;
  557. $p4 = -0.453642210148e-4;
  558. $q0 = 0.0993484626060;
  559. $q1 = 0.588581570495;
  560. $q2 = 0.531103462366;
  561. $q3 = 0.103537752850;
  562. $q4 = 0.38560700634e-2;
  563. if ($p < 0.5) { $pp = $p; } else {$pp = 1 - $p; }
  564. if ($pp < 1E-12) {
  565. $xp = 99;
  566. } else {
  567. $y = sqrt(log(1/($pp*$pp)));
  568. $xp = $y + (((($y * $p4 + $p3) * $y + $p2) * $y + $p1) * $y + $p0) / (((($y * $q4 + $q3) * $y + $q2) * $y + $q1) * $y + $q0);
  569. }
  570. $xp = round($xp,$dec);
  571. if ($p < 0.5) { return (-1*$xp); } else { return $xp; }
  572. }
  573. //invtcdf(p,df,[dec])
  574. //the inverse Student's t-distribution
  575. //computes the t-value with a left-tail probability of p, with df degrees of freedom
  576. //to dec decimal places (default 4)
  577. // from Algorithm 396: Student's t-quantiles by G.W. Hill Comm. A.C.M., vol.13(10), 619-620, October 1970
  578. function invtcdf($p,$ndf,$dec=4) {
  579. $half_pi = M_PI/2;
  580. $eps = 1e-12;
  581. $origp = $p;
  582. if ($p > 0.5) {$p = 1 - $p; }
  583. $p = $p*2;
  584. if ($ndf < 1 || $p > 1 || $p <= 0) {
  585. echo "error in params";
  586. return false;
  587. }
  588. if ( abs($ndf - 2) < $eps ) { //special case ndf=2
  589. $fn_val = round(SQRT(2 / ( $p * (2 - $p) ) - 2),$dec);
  590. if ($origp<.5) {return (-1*$fn_val);} else { return $fn_val;}
  591. } else if (abs($ndf-4) < $eps) { //special case ndf=4
  592. $v = 4/sqrt($p*(2-$p))*cos(1/3*acos(sqrt($p*(2-$p))));
  593. $fn_val = round(sqrt($v-4),$dec);
  594. if ($origp<.5) {return (-1*$fn_val);} else { return $fn_val;}
  595. } else if ($ndf < 1+$eps) { //special case ndf=1
  596. $prob = $p * $half_pi;
  597. $fn_val = round(cos($prob) / sin($prob),$dec);
  598. if ($origp<.5) {return (-1*$fn_val);} else { return $fn_val;}
  599. } else {
  600. $a = 1/ ($ndf - 0.5);
  601. $b = 48/ pow($a,2);
  602. $c = ((20700 * $a / $b - 98) * $a - 16) * $a + 96.36;
  603. $d = ((94.5 / ($b + $c) - 3) / $b + 1) * sqrt($a * $half_pi)* $ndf;
  604. $x = $d * $p;
  605. $y = pow($x,(2/ $ndf));
  606. if ($y > 0.05 + $a) {
  607. $x = invnormalcdf($origp,$dec+10);
  608. $y = pow($x,2);
  609. if ($ndf < 5) { $c = $c + 0.3 * ($ndf - 4.5) * ($x + 0.6);}
  610. $c = (((0.05 * $d * $x - 5) * $x - 7) * $x - 2) * $x + $b+ $c;
  611. $y = (((((0.4*$y + 6.3) * $y + 36) * $y + 94.5) / $c - $y - 3) / $b + 1) * $x;
  612. $y = $a * pow($y,2);
  613. if ($y > 0.002) {
  614. $y = exp($y) - 1;
  615. } else {
  616. $y = 0.5 * pow($y,2) + $y;
  617. }
  618. } else {
  619. $y = ((1 / ((($ndf + 6) / ($ndf * $y) - 0.089 * $d - 0.822) * ($ndf + 2) * 3) + 0.5 / ($ndf + 4)) * $y - 1) * ($ndf + 1) / ($ndf + 2) + 1 / $y;
  620. }
  621. }
  622. if ($dec>3) {
  623. $fn_val = invtrefine(sqrt($ndf*$y),1-$p/2,$ndf,$dec);
  624. //echo "orig: ".sqrt($ndf*$y).", refined: $fn_val <br/>";
  625. } else {
  626. $fn_val = round( sqrt($ndf * $y) , $dec);
  627. }
  628. if ($origp<.5) {return (-1*$fn_val);} else { return $fn_val;}
  629. }
  630. function invtrefine($t,$p,$ndf,$dec) {
  631. $dv = .001;
  632. $eps = pow(.1,$dec+1);
  633. while ($dv>$eps) {
  634. $dv = $dv/2;
  635. if (tcdf($t,$ndf,$dec+10)>$p) {
  636. $t = $t-$dv;
  637. } else {
  638. $t = $t+$dv;
  639. }
  640. }
  641. return round($t,$dec);
  642. }
  643. //linreg(xarray,yarray)
  644. //Computes the linear correlation coefficient, and slope and intercept of
  645. //regression line, based on array/list of x-values and array/list of y-values
  646. //Returns as array: r,slope,intercept
  647. function linreg($xarr,$yarr) {
  648. if (!is_array($xarr)) { $xarr = explode(',',$xarr);}
  649. if (!is_array($yarr)) { $yarr = explode(',',$yarr);}
  650. if (count($xarr)!=count($yarr)) {
  651. echo "Error: linreg requires xarray length = yarray length";
  652. return false;
  653. }
  654. $sx = array_sum($xarr);
  655. $sy = array_sum($yarr);
  656. $sxx=0; $syy=0; $sxy = 0;
  657. for ($i=0; $i<count($xarr); $i++) {
  658. $sxx += $xarr[$i]*$xarr[$i];
  659. $syy += $yarr[$i]*$yarr[$i];
  660. $sxy += $xarr[$i]*$yarr[$i];
  661. }
  662. $n = count($xarr);
  663. $r = ($n*$sxy - $sx*$sy)/(sqrt($n*$sxx-$sx*$sx)*sqrt($n*$syy-$sy*$sy));
  664. $m = ($n*$sxy - $sx*$sy)/($n*$sxx - $sx*$sx);
  665. $b = ($sy - $sx*$m)/$n;
  666. return array($r,$m,$b);
  667. }
  668. //binomialpdf(N,p,x)
  669. //Computes the probability of x successes out of N trials
  670. //where each trial has probability p of success
  671. function binomialpdf($N,$p,$x) {
  672. return (nCr($N,$x)*pow($p,$x)*pow(1-$p,$N-$x));
  673. }
  674. //binomialcdf(N,p,x)
  675. //Computes the probably of &lt;=x successes out of N trials
  676. //where each trial has probability p of success
  677. function binomialcdf($N,$p,$x) {
  678. $out = 0;
  679. for ($i=0;$i<=$x;$i++) {
  680. $out += binomialpdf($N,$p,$i);
  681. }
  682. return $out;
  683. }
  684. //chi2cdf(x,df)
  685. //Computes the area to the left of x under the chi-squared disribution
  686. //with df degrees of freedom
  687. function chi2cdf($x,$a) {
  688. return gamma_cdf(0.5*$x,0.0,1.0,0.5*$a);
  689. }
  690. function chicdf($x,$a) {
  691. return gamma_cdf(0.5*$x,0.0,1.0,0.5*$a);
  692. }
  693. function invchicdf($cdf,$a) {
  694. return invchi2cdf($cdf,$a);
  695. }
  696. //invchi2cdf(p,df)
  697. //Compuates the x value with left-tail probability p under the
  698. //chi-squared distribution with df degrees of freedom
  699. function invchi2cdf($cdf,$a) {
  700. $aa = 0.6931471806;
  701. $c1 = 0.01;
  702. $c2 = 0.222222;
  703. $c3 = 0.32;
  704. $c4 = 0.4;
  705. $c5 = 1.24;
  706. $c6 = 2.2;
  707. $c7 = 4.67;
  708. $c8 = 6.66;
  709. $c9 = 6.73;
  710. $c10 = 13.32;
  711. $c11 = 60.0;
  712. $c12 = 70.0;
  713. $c13 = 84.0;
  714. $c14 = 105.0;
  715. $c15 = 120.0;
  716. $c16 = 127.0;
  717. $c17 = 140.0;
  718. $c18 = 175.0;
  719. $c19 = 210.0;
  720. $c20 = 252.0;
  721. $c21 = 264.0;
  722. $c22 = 294.0;
  723. $c23 = 346.0;
  724. $c24 = 420.0;
  725. $c25 = 462.0;
  726. $c26 = 606.0;
  727. $c27 = 672.0;
  728. $c28 = 707.0;
  729. $c29 = 735.0;
  730. $c30 = 889.0;
  731. $c31 = 932.0;
  732. $c32 = 966.0;
  733. $c33 = 1141.0;
  734. $c34 = 1182.0;
  735. $c35 = 1278.0;
  736. $c36 = 1740.0;
  737. $c37 = 2520.0;
  738. $c38 = 5040.0;
  739. $cdf_max = 0.999998;
  740. $cdf_min = 0.000002;
  741. $e = 0.0000005;
  742. $it_max = 20;
  743. if ($cdf < $cdf_min) {
  744. echo "p < min - can't do it!";
  745. return 0;
  746. }
  747. if ($cdf_max < $cdf) {
  748. echo "p > max - can't do it";
  749. return 0;
  750. }
  751. $xx = 0.5*$a;
  752. $c = $xx-1.0;
  753. $g = gamma_log($a/2.0);
  754. if ($a < -$c5*log($cdf)) {
  755. $ch = pow(($cdf*$xx*exp($g+$xx*$aa)),(1.0/$xx));
  756. if ($ch < $e) {
  757. $x = $ch;
  758. return $x;
  759. }
  760. } else if ($a <= $c3) {
  761. $ch = $c4;
  762. $a2 = log(1.0 - $cdf);
  763. while (1) {
  764. $q = $ch;
  765. $p1 = 1.0+$ch*($c7 + $ch);
  766. $p2 = $ch*($c9 + $ch*($c8+$ch));
  767. $t = -0.5+($c7 + 2.0*$ch)/$p1 - ($c9 + $ch*($c10 + 3.0*$ch)) / $p2;
  768. $ch = $ch - (1.0 - exp($a2 + $g + 0.5*$ch + $c*$aa)*$p2/$p1)/$t;
  769. if (abs($q/$ch - 1.0) <= $c1) {
  770. break;
  771. }
  772. }
  773. } else {
  774. $x2 = invnormalcdf($cdf);
  775. $p1 = $c2/$a;
  776. $ch = $a*pow(($x2*sqrt($p1) + 1.0 - $p1),3);
  777. if ($c6*$a + 6.0 < $ch) {
  778. $ch = -2.0*(log(1.0 - $cdf) - $c*log(0.5*$ch)+$g);
  779. }
  780. }
  781. for ($i=1;$i<=$it_max;$i++) {
  782. $q = $ch;
  783. $p1 = 0.5*$ch;
  784. $p2 = $cdf - gamma_inc($xx,$p1);
  785. $t = $p2*exp($xx*$aa + $g + $p1 - $c*log($ch));
  786. $b = $t/$ch;
  787. $a2 = 0.5*$t - $b*$c;
  788. $s1 = ($c19 + $a2 * ($c17 + $a2 * ($c14 + $a2 *($c13 + $a2 * ($c12 + $a2 * $c11))))) / $c24;
  789. $s2 = ($c24 + $a2 * ($c29 + $a2 * ($c32 + $a2 *($c33 + $a2 * $c35)))) / $c37;
  790. $s3 = ($c19 + $a2 * ($c25 + $a2 * ($c28 + $a2 * $c31)))/$c37;
  791. $s4 = ($c20 + $a2 * ($c27 + $a2 * $c34) + $c * ($c22 + $a2 * ($c30 + $a2 *$c36)))/$c38;
  792. $s5 = ($c13 + $c21 + $a2 + $c * ($c18 + $c26 * $a2))/$c37;
  793. $s6 = ($c16 + $c*($c23 + $c16*$c))/$c38;
  794. $ch = $ch + $t*(1.0 + 0.5*$t*$s1 - $b*$c * ($s1-$b*($s2-$b*($s3-$b*($s4-$b*($s5-$b*$s6))))));
  795. if ($e < abs($q/$ch - 1.0)) {
  796. $x = $ch;
  797. return ($x);
  798. }
  799. }
  800. $x = $ch;
  801. echo "Convergence not reached in invchisquare";
  802. return $x;
  803. }
  804. function gamma_cdf($x,$a,$b,$c) {
  805. return gamma_inc($c,($x-$a)/$b);
  806. }
  807. function gamma_inc($p,$x,$dec=4) {
  808. $exp_arg_min = -88.0;
  809. $overflow = 1e37;
  810. $plimit = 1000;
  811. $tol = 1e-7;
  812. $xbig = 1e8;
  813. $value = 0.0;
  814. if ($plimit<$p) {
  815. $pn1 = 3.0*sqrt($p)*(pow($x/$p,1.0/3.0) + 1.0/(9.0*$p)-1.0);
  816. $value = normalcdf($pn1,$dec);
  817. return $value;
  818. }
  819. if ($xbig<$x) {
  820. return 1.0;
  821. }
  822. if ($x<=1.0 || $x<$p) {
  823. $arg = $p*log($x) - $x - gamma_log($p+1.0);
  824. $c = 1.0;
  825. $value = 1.0;
  826. $a = $p;
  827. while ($c>$tol) {
  828. $a += 1.0;
  829. $c = $c*$x/$a;
  830. $value += $c;
  831. }
  832. $arg += log($value);
  833. if ($exp_arg_min <= $arg) {
  834. $value = exp($arg);
  835. } else {
  836. $value = 0.0;
  837. }
  838. } else {
  839. $arg = $p*log($x)-$x-gamma_log($p);
  840. $a = 1.0 - $p;
  841. $b = $a+$x+1.0;
  842. $c = 0.0;
  843. $pn1 = 1.0;
  844. $pn2 = $x;
  845. $pn3 = $x+1.0;
  846. $pn4 = $x*$b;
  847. $value = $pn3/$pn4;
  848. while (1) {
  849. $a += 1.0;
  850. $b += 2.0;
  851. $c += 1.0;
  852. $pn5 = $b*$pn3 - $a*$c*$pn1;
  853. $pn6 = $b*$pn4 - $a*$c*$pn2;
  854. if (0 < abs($pn6)) {
  855. $rn = $pn5/$pn6;
  856. if (abs($value-$rn) <= min($tol,$tol*$rn)) {
  857. $arg += log($value);
  858. if ($exp_arg_min <= $arg) {
  859. $value = 1.0 - exp($arg);
  860. } else {
  861. $value = 1.0;
  862. }
  863. return $value;
  864. }
  865. $value = $rn;
  866. }
  867. $pn1 = $pn3;
  868. $pn2 = $pn4;
  869. $pn3 = $pn5;
  870. $pn4 = $pn6;
  871. if ($overflow <= abs($pn5)) {
  872. $pn1 = $pn1/$overflow;
  873. $pn2 = $pn2/$overflow;
  874. $pn3 = $pn3/$overflow;
  875. $pn4 = $pn4/$overflow;
  876. }
  877. }
  878. }
  879. return $value;
  880. }
  881. function gamma_log($x) {
  882. $c = array(
  883. -1.910444077728E-03,
  884. 8.4171387781295E-04,
  885. -5.952379913043012E-04,
  886. 7.93650793500350248E-04,
  887. -2.777777777777681622553E-03,
  888. 8.333333333333333331554247E-02,
  889. 5.7083835261E-03 );
  890. $d1 = - 5.772156649015328605195174E-01;
  891. $d2 = 4.227843350984671393993777E-01;
  892. $d4 = 1.791759469228055000094023;
  893. $frtbig = 1.42E+09;
  894. $p1 = array(
  895. 4.945235359296727046734888,
  896. 2.018112620856775083915565E+02,
  897. 2.290838373831346393026739E+03,
  898. 1.131967205903380828685045E+04,
  899. 2.855724635671635335736389E+04,
  900. 3.848496228443793359990269E+04,
  901. 2.637748787624195437963534E+04,
  902. 7.225813979700288197698961E+03 );
  903. $p2 = array(
  904. 4.974607845568932035012064,
  905. 5.424138599891070494101986E+02,
  906. 1.550693864978364947665077E+04,
  907. 1.847932904445632425417223E+05,
  908. 1.088204769468828767498470E+06,
  909. 3.338152967987029735917223E+06,
  910. 5.106661678927352456275255E+06,
  911. 3.074109054850539556250927E+06 );
  912. $p4 = array(
  913. 1.474502166059939948905062E+04,
  914. 2.426813369486704502836312E+06,
  915. 1.214755574045093227939592E+08,
  916. 2.663432449630976949898078E+09,
  917. 2.940378956634553899906876E+010,
  918. 1.702665737765398868392998E+011,
  919. 4.926125793377430887588120E+011,
  920. 5.606251856223951465078242E+011 );
  921. $pnt68 = 0.6796875;
  922. $q1 = array(
  923. 6.748212550303777196073036E+01,
  924. 1.113332393857199323513008E+03,
  925. 7.738757056935398733233834E+03,
  926. 2.763987074403340708898585E+04,
  927. 5.499310206226157329794414E+04,
  928. 6.161122180066002127833352E+04,
  929. 3.635127591501940507276287E+04,
  930. 8.785536302431013170870835E+03 );
  931. $q2 = array(
  932. 1.830328399370592604055942E+02,
  933. 7.765049321445005871323047E+03,
  934. 1.331903827966074194402448E+05,
  935. 1.136705821321969608938755E+06,
  936. 5.267964117437946917577538E+06,
  937. 1.346701454311101692290052E+07,
  938. 1.782736530353274213975932E+07,
  939. 9.533095591844353613395747E+06 );
  940. $q4 = array(
  941. 2.690530175870899333379843E+03,
  942. 6.393885654300092398984238E+05,
  943. 4.135599930241388052042842E+07,
  944. 1.120872109616147941376570E+09,
  945. 1.488613728678813811542398E+010,
  946. 1.016803586272438228077304E+011,
  947. 3.417476345507377132798597E+011,
  948. 4.463158187419713286462081E+011 );
  949. $sqrtpi = 0.9189385332046727417803297;
  950. $xbig = 4.08E+36;
  951. if ($x<=0 || $xbig < $x) {
  952. return 1e10;
  953. }
  954. if ($x <= 1e-10) {
  955. $res = -log($x);
  956. } else if ($x<=1.5) {
  957. if ($x<$pnt68) {
  958. $corr = -log($x);
  959. $xm1 = $x;
  960. } else {
  961. $corr = 0.0;
  962. $xm1 = ($x-0.5) - 0.5;
  963. }
  964. if ($x<0.5 || $pnt68 <= $x) {
  965. $xden = 1.0;
  966. $xnum = 0.0;
  967. for ($i=0; $i<8; $i++) {
  968. $xnum = $xnum*$xm1 + $p1[$i];
  969. $xden = $xden*$xm1 + $q1[$i];
  970. }
  971. $res = $corr + ($xm1*($d1 + $xm1*($xnum/$xden)));
  972. } else {
  973. $xm2 = ($x-0.5)-0.5;
  974. $xden = 1.0;
  975. $xnum = 0.0;
  976. for ($i=0; $i<8; $i++) {
  977. $xnum = $xnum*$xm2 + $p2[$i];
  978. $xden = $xden*$xm2 + $q2[$i];
  979. }
  980. $res = $corr + ($xm2*($d2 + $xm2*($xnum/$xden)));
  981. }
  982. } else if ($x<=4.0) {
  983. $xm2 = $x-2.0;
  984. $xden = 1.0;
  985. $xnum = 0.0;
  986. for ($i=0; $i<8; $i++) {
  987. $xnum = $xnum*$xm2 + $p2[$i];
  988. $xden = $xden*$xm2 + $q2[$i];
  989. }
  990. $res = $xm2*($d2 + $xm2*($xnum/$xden));
  991. } else if ($x <= 12.0) {
  992. $xm4 = $x - 4.0;
  993. $xden = -1.0;
  994. $xnum = 0.0;
  995. for ($i=0; $i<8; $i++) {
  996. $xnum = $xnum*$xm4 + $p4[$i];
  997. $xden = $xden*$xm4 + $q4[$i];
  998. }
  999. $res = $d4 + $xm4*($xnum/$xden);
  1000. } else {
  1001. $res = 0.0;
  1002. if ($x<= $frtbig) {
  1003. $res = $c[6];
  1004. $xsq = $x*$x;
  1005. for ($i=0;$i<6;$i++) {
  1006. $res = $res/$xsq + $c[$i];
  1007. }
  1008. }
  1009. $res = $res/$x;
  1010. $corr = log($x);
  1011. $res = $res + $sqrtpi - 0.5*$corr;
  1012. $res = $res + $x*($corr - 1.0);
  1013. }
  1014. return $res;
  1015. }
  1016. //fcdf(f,df1,df2)
  1017. //Returns the area to right of the F-value f for the f-distribution
  1018. //with df1 and df2 degrees of freedom (techinically it's 1-CDF)
  1019. //Algorithm is accurate to approximately 4-5 decimals
  1020. function fcdf($x,$df1,$df2) {
  1021. $p1 = fcall(fspin($x,$df1,$df2));
  1022. return $p1;
  1023. }
  1024. function fcall($x) {
  1025. if ($x>=0) {
  1026. $x += 0.0000005;
  1027. } else {
  1028. $x -= 0.0000005;
  1029. }
  1030. return $x;
  1031. }
  1032. function fspin($f,$df1,$df2) {
  1033. $pj2 = M_PI/2;
  1034. $pj4 = M_PI/4;
  1035. $px2 = 2*M_PI;
  1036. $exx = 1.10517091807564;
  1037. $dgr = 180/M_PI;
  1038. $x = $df2/($df1*$f+$df2);
  1039. if (($df1%2)==0) {
  1040. return (LJspin(1-$x,$df2,$df1+$df2-4,$df2-2)*pow($x,$df2/2));
  1041. } else if (($df2%2)==0) {
  1042. return (1-LJspin($x,$df1,$df1+$df2-4,$df1-2)*pow(1-$x,$df1/2));
  1043. }
  1044. $tan = atan(sqrt($df1*$f/$df2));
  1045. $a = $tan/$pj2;
  1046. $sat = sin($tan);
  1047. $cot = cos($tan);
  1048. if ($df2>1) {
  1049. $a = $a+$sat*$cot*LJspin($cot*$cot,2,$df2-3,-1)/$pj2;
  1050. }
  1051. if ($df1==1) {
  1052. return (1-$a);
  1053. }
  1054. $c = 4*LJspin($sat*$sat,$df2+1,$df1+$df2-4,$df2-2)*$sat*pow($cot,$df2)/M_PI;
  1055. if ($df2==1) {
  1056. return (1-$a+$c/2);
  1057. }
  1058. $k = 2;
  1059. while ($k<=($df2-1)/2) {
  1060. $c = $c*$k/($k-0.5);
  1061. $k++;
  1062. }
  1063. return (1-$a+$c);
  1064. }
  1065. function LJspin($q,$i,$j,$b) {
  1066. $zz = 1;
  1067. $z = $zz;
  1068. $k = $i;
  1069. while ($k<=$j) {
  1070. $zz = $zz*$q*$k/($k-$b);
  1071. $z = $z+$zz;
  1072. $k += 2;
  1073. }
  1074. return $z;
  1075. }
  1076. //invfcdf(p,df1,df2)
  1077. //Computes the f-value with probability of p to the right
  1078. //with degrees of freedom df1 and df2
  1079. //Algorithm is accurate to approximately 2-4 decimal places
  1080. //Less accurate for smaller p-values
  1081. function invfcdf($p,$df1,$df2) {
  1082. $v = 0.5;
  1083. $dv = 0.5;
  1084. $f = 0;
  1085. $cnt = 0;
  1086. while ($dv>1e-10) {
  1087. $f = 1/$v-1;
  1088. $dv = $dv/2;
  1089. if (fcdf($f,$df1,$df2)>$p) {
  1090. $v = $v-$dv;
  1091. } else {
  1092. $v = $v+$dv;
  1093. }
  1094. $cnt++;
  1095. }
  1096. return $f;
  1097. }
  1098. ?>