// Percentile Point Function from http://spechal.com/2009/11/15/php-function-to-emulate-excel-normsinv/

function Z($p){

$a1 = -39.6968302866538; $a2 = 220.946098424521; $a3 = -275.928510446969;

$a4 = 138.357751867269; $a5 = -30.6647980661472; $a6 = 2.50662827745924;

$b1 = -54.4760987982241; $b2 = 161.585836858041; $b3 = -155.698979859887;

$b4 = 66.8013118877197; $b5 = -13.2806815528857; $c1 = -7.78489400243029E-03;

$c2 = -0.322396458041136; $c3 = -2.40075827716184; $c4 = -2.54973253934373;

$c5 = 4.37466414146497; $c6 = 2.93816398269878; $d1 = 7.78469570904146E-03;

$d2 = 0.32246712907004; $d3 = 2.445134137143; $d4 = 3.75440866190742;

$p_low = 0.02425; $p_high = 1 - $p_low;

$q = 0.0; $r = 0.0;

if($p < 0 || $p > 1) throw new Exception("NormSInv: Argument out of range.");

else if($p < $p_low){

$q = pow(-2 * log($p), 2);

$ppf = ((((($c1 * $q + $c2) * $q + $c3) * $q + $c4) * $q + $c5) * $q + $c6) / (((($d1 * $q + $d2) * $q + $d3) * $q + $d4) * $q + 1);

}

else if($p <= $p_high){

$q = $p - 0.5; $r = $q * $q;

$ppf = ((((($a1 * $r + $a2) * $r + $a3) * $r + $a4) * $r + $a5) * $r + $a6) * $q / ((((($b1 * $r + $b2) * $r + $b3) * $r + $b4) * $r + $b5) * $r + 1);

}

else {

$q = pow(-2 * log(1 - $p), 2);

$ppf = -((((($c1 * $q + $c2) * $q + $c3) * $q + $c4) * $q + $c5) * $q + $c6) / (((($d1 * $q + $d2) * $q + $d3) * $q + $d4) * $q + 1);

}

return $ppf;

}

// Credit to comment on http://php.net/manual/en/function.stats-stat-percentile.php

function erf($x) {

$pi = 3.1415927;

$a = (8*($pi - 3))/(3*$pi*(4 - $pi));

$x2 = $x * $x;

$ax2 = $a * $x2;

$num = (4/$pi) + $ax2;

$denom = 1 + $ax2;

$inner = (-$x2)*$num/$denom;

$erf2 = 1 - exp($inner);

return sqrt($erf2);

}

function cdf($n) {

if($n < 0) return (1 - erf($n / sqrt(2)))/2;

else return (1 + erf($n / sqrt(2)))/2;

}

// Calculate d' and avoid infinity

function dPrime($hits, $misses, $fas, $crs) {

$half_miss = 0.5/($hits+$misses);

$half_fa = 0.5/($fas+$crs);

$hitrate = $hits/($hits+$misses);

$farate = $fas/($fas+$crs);

// Avoid d' negative infinity

if($hitrate < 0.025) {

if($hitrate+$half_miss < 0.025) $hitrate = 0.025;

else $hitrate = $half_miss;

}

if($farate < 0.025) {

if($farate+$half_fa < 0.025) $farate = 0.025;

else $farate = $half_fa;

}

// Avoid d' infinity

if($hitrate > 0.975) {

if($hitrate-$half_miss > 0.975) $hitrate = 0.975;

else $hitrate = 1-$half_miss;

}

if($farate > 0.975) {

if($farate-$half_fa > 0.975) $farate = 0.975;

else $farate = 1-$half_fa;

}

// Calculate d' using Percentile Point function

$out = new stdClass;

$out->d = Z($hitrate)-Z($farate);

$out->beta = exp(pow(Z($farate),2) - pow(Z($hitrate),2))/2;

$out->c = -(Z($hitrate)+Z($farate))/2;

$out->Ad = cdf($out->d/sqrt(2));

return $out;

}