PHP には erf(), erfc() がなかったので、Ruby に Math.erf(), Math.erfc() として実装されている C のソース を PHP に移植しました。プログラムは自由に使用ください。
<?php
/*
reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten
(New Algorithm handbook in C language) (Gijyutsu hyouronsha, Tokyo, 1991) p.227 [in Japanese]
C source (for Ruby Interpreter)
http://www.google.com/codesearch?hl=ja&q=+show:i7gZ8RAuObo:ErgYZrNE2TI:1koF_ZMUv9Q&
sa=N&cd=2&ct=rc&cs_p=ftp://ftp.sunfreeware.com/pub/freeware/SOURCES/ruby-1.8.6.tar.gz&
cs_f=ruby-1.8.6/missing/erf.c
*/
/* Incomplete gamma function 1 / Gamma(a) * Int_0^x exp(-t) t^(a-1) dt */
function p_gamma($a,$x,$loggamma_a){
if($x>=1+$a){ return(1-q_gamma($a,$x,$loggamma_a)); }
if($x==0){ return(0); }
$result=$term=exp($a*log($x)-$x-$loggamma_a)/$a;
for($k=1;$k<1000;$k++){
$term*=$x/($a+$k);
$previous=$result;
$result+=$term;
if($result==$previous){ return($result); }
}
trigger_error("d:p_gamma() could not converge.");
return($result);
}
/* Incomplete gamma function 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */
function q_gamma($a,$x,$loggamma_a){
$la=1;
$lb=1+$x-$a; /* Laguerre polynomial */
if($x<1+$a){ return(1-p_gamma($a,$x,$loggamma_a)); }
$w=exp($a*log($x)-$x-$loggamma_a);
$result=$w/$lb;
for ($k=2;$k<1000;$k++) {
$temp=(($k-1-$a)*($lb-$la)+($k+$x)*$lb)/$k;
$la=$lb;
$lb=$temp;
$w*=($k-1-$a)/$k;
$temp=$w/($la*$lb);
$previous=$result;
$result+=$temp;
if($result==$previous){ return($result); }
}
trigger_error("d:q_gamma() could not converge.");
return($result);
}
define(LOG_PI_OVER_2,0.572364942924700087071713675675); /* log_e(PI)/2 */
function erf($x){
if(!is_finite($x)){
if(is_nan($x)){ return($x); } /* erf(NaN) = NaN */
return($x>0 ? 1.0 : -1.0); /* erf(+-inf) = +-1.0 */
}
if($x>=0){ return(p_gamma(0.5,$x*$x, LOG_PI_OVER_2)); }
else{ return(-1*p_gamma(0.5,$x*$x, LOG_PI_OVER_2)); }
}
function erfc($x){
if(!is_finite($x)){
if(is_nan($x)){return($x); } /* erfc(NaN) = NaN */
return($x>0 ? 0.0 : 2.0); /* erfc(+-inf) = 0.0, 2.0 */
}
if($x>=0){ return(q_gamma(0.5,$x*$x,LOG_PI_OVER_2)); }
else{ return(1+p_gamma(0.5,$x*$x,LOG_PI_OVER_2)); }
}
/* 実行結果 */
echo("erf(-2.0)=".erf(-2.0)."<br />"); // erf(-2.0)=-0.99532226501895
echo("erf(-1.6)=".erf(-1.6)."<br />"); // erf(-1.6)=-0.97634838334464
echo("erf(-1.2)=".erf(-1.2)."<br />"); // erf(-1.2)=-0.91031397822964
echo("erf(-0.8)=".erf(-0.8)."<br />"); // erf(-0.8)=-0.74210096470766
echo("erf(-0.4)=".erf(-0.4)."<br />"); // erf(-0.4)=-0.42839235504667
echo("erf(0.0)=".erf(0.0)."<br />"); // erf(0.0)=0
echo("erf(0.4)=".erf(0.4)."<br />"); // erf(0.4)=0.42839235504667
echo("erf(0.8)=".erf(0.8)."<br />"); // erf(0.8)=0.74210096470766
echo("erf(1.2)=".erf(1.2)."<br />"); // erf(1.2)=0.91031397822964
echo("erf(1.6)=".erf(1.6)."<br />"); // erf(1.6)=0.97634838334464
echo("erf(2.0)=".erf(2.0)."<br />"); // erf(2.0)=0.99532226501895
echo("erfc(-2.0)=".erfc(-2.0)."<br />"); // erfc(-2.0)=1.995322265019
echo("erfc(-1.6)=".erfc(-1.6)."<br />"); // erfc(-1.6)=1.9763483833446
echo("erfc(-1.2)=".erfc(-1.2)."<br />"); // erfc(-1.2)=1.9103139782296
echo("erfc(-0.8)=".erfc(-0.8)."<br />"); // erfc(-0.8)=1.7421009647077
echo("erfc(-0.4)=".erfc(-0.4)."<br />"); // erfc(-0.4)=1.4283923550467
echo("erfc(0.0)=".erfc(0.0)."<br />"); // erfc(0.0)=1
echo("erfc(0.4)=".erfc(0.4)."<br />"); // erfc(0.4)=0.57160764495333
echo("erfc(0.8)=".erfc(0.8)."<br />"); // erfc(0.8)=0.25789903529234
echo("erfc(1.2)=".erfc(1.2)."<br />"); // erfc(1.2)=0.089686021770365
echo("erfc(1.6)=".erfc(1.6)."<br />"); // erfc(1.6)=0.023651616655356
echo("erfc(2.0)=".erfc(2.0)."<br />"); // erfc(2.0)=0.0046777349810473
?>