struct Erf { static const Int ncof=28; static const Doub cof[28]; inline Doub erf(Doub x) { if (x >=0.) return 1.0 - erfccheb(x); else return erfccheb(-x) - 1.0; } inline Doub erfc(Doub x) { if (x >= 0.) return erfccheb(x); else return 2.0 - erfccheb(-x); } Doub erfccheb(Doub z){ Int j; Doub t,ty,tmp,d=0.,dd=0.; if (z < 0.) throw("erfccheb requires nonnegative argument"); t = 2./(2.+z); ty = 4.*t - 2.; for (j=ncof-1;j>0;j--) { tmp = d; d = ty*d - dd + cof[j]; dd = tmp; } return t*exp(-z*z + 0.5*(cof[0] + ty*d) - dd); } Doub inverfc(Doub p) { Doub x,err,t,pp; if (p >= 2.0) return -100.; if (p <= 0.0) return 100.; pp = (p < 1.0)? p : 2. - p; t = sqrt(-2.*log(pp/2.)); x = -0.70711*((2.30753+t*0.27061)/(1.+t*(0.99229+t*0.04481)) - t); for (Int j=0;j<2;j++) { err = erfc(x) - pp; x += err/(1.12837916709551257*exp(-SQR(x))-x*err); } return (p < 1.0? x : -x); } inline Doub inverf(Doub p) {return inverfc(1.-p);} }; const Doub Erf::cof[28] = {-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,-9.561514786808631e-3,-9.46595344482036e-4, 3.66839497852761e-4,4.2523324806907e-5,-2.0278578112534e-5, -1.624290004647e-6,1.303655835580e-6,1.5626441722e-8,-8.5238095915e-8, 6.529054439e-9,5.059343495e-9,-9.91364156e-10,-2.27365122e-10, 9.6467911e-11, 2.394038e-12,-6.886027e-12,8.94487e-13, 3.13092e-13, -1.12708e-13,3.81e-16,7.106e-15,-1.523e-15,-9.4e-17,1.21e-16,-2.8e-17}; Doub erfcc(const Doub x) { Doub t,z=fabs(x),ans; t=2./(2.+z); ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+ t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+ t*(-0.82215223+t*0.17087277))))))))); return (x >= 0.0 ? ans : 2.0-ans); } struct Normaldist : Erf { Doub mu, sig; Normaldist(Doub mmu = 0., Doub ssig = 1.) : mu(mmu), sig(ssig) { if (sig <= 0.) throw("bad sig in Normaldist"); } Doub p(Doub x) { return (0.398942280401432678/sig)*exp(-0.5*SQR((x-mu)/sig)); } Doub cdf(Doub x) { return 0.5*erfc(-0.707106781186547524*(x-mu)/sig); } Doub invcdf(Doub p) { if (p <= 0. || p >= 1.) throw("bad p in Normaldist"); return -1.41421356237309505*sig*inverfc(2.*p)+mu; } }; struct Lognormaldist : Erf { Doub mu, sig; Lognormaldist(Doub mmu = 0., Doub ssig = 1.) : mu(mmu), sig(ssig) { if (sig <= 0.) throw("bad sig in Lognormaldist"); } Doub p(Doub x) { if (x < 0.) throw("bad x in Lognormaldist"); if (x == 0.) return 0.; return (0.398942280401432678/(sig*x))*exp(-0.5*SQR((log(x)-mu)/sig)); } Doub cdf(Doub x) { if (x < 0.) throw("bad x in Lognormaldist"); if (x == 0.) return 0.; return 0.5*erfc(-0.707106781186547524*(log(x)-mu)/sig); } Doub invcdf(Doub p) { if (p <= 0. || p >= 1.) throw("bad p in Lognormaldist"); return exp(-1.41421356237309505*sig*inverfc(2.*p)+mu); } };