[
https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13086014#comment-13086014
]
Christian Winter commented on MATH-364:
---------------------------------------
Here's the new suggestion:
{code}
public static double erf(double x1, double x2) {
if(x1 > x2) {
return -erf(x2, x1);
}
/**
* The number {@code x_crit} solves {@code erf(x)=0.5} within 1ulp.
* More precisely, the current implementations of
* {@link #erf(double)} and {@link #erfc(double)} satisfy:<br/>
* {@code erf(x_crit) < 0.5},<br/>
* {@code erf(Math.nextUp(x_crit) > 0.5},<br/>
* {@code erfc(x_crit) = 0.5}, and<br/>
* {@code erfc(Math.nextUp(x_crit) < 0.5}
*/
double x_crit = 0.4769362762044697;
return
x1 < -x_crit && x2 < 0.0 ?
erfc(-x2) - erfc(-x1)
: x2 > x_crit && x1 > 0.0 ?
erfc(x1) - erfc(x2)
:
erf(x2) - erf(x1);
}
{code}
Following the idea to keep numbers small during calculation, the stragegies for
{{x1,x2 < -x_crit}}, {{x1,x2 > x_crit}}, and {{|x1|,|x2| ≤ x_crit}} are
straightforward and mandatory. In the other cases, numbers ≥ 0.5 cannot be
avoided and there is some freedom of choice. The suggested code avoids number
≥ 1 where the final result is < 1.
> Make Erf more precise in the tails by providing erfc
> ----------------------------------------------------
>
> Key: MATH-364
> URL: https://issues.apache.org/jira/browse/MATH-364
> Project: Commons Math
> Issue Type: Improvement
> Affects Versions: 1.1, 1.2, 2.0, 2.1
> Reporter: Christian Winter
> Priority: Minor
> Fix For: 3.0
>
>
> First I want to thank Phil Steitz for making Erf stable in the tails through
> adjusting the choices in calculating the regularized gamma functions, see
> [Math-282|https://issues.apache.org/jira/browse/MATH-282]. However, the
> precision of Erf in the tails is limitted to fixed point precision because of
> the closeness to +/-1.0, although the Gamma class could provide much more
> accuracy. Thus I propose to add the methods erfc(double) and erf(double,
> double) to the class Erf:
> {code:borderStyle=solid}
> /**
> * Returns the complementary error function erfc(x).
> * @param x the value
> * @return the complementary error function erfc(x)
> * @throws MathException if the algorithm fails to converge
> */
> public static double erfc(double x) throws MathException {
> double ret = Gamma.regularizedGammaQ(0.5, x * x, 1.0e-15, 10000);
> if (x < 0) {
> ret = -ret;
> }
> return ret;
> }
> /**
> * Returns the difference of the error function values of x1 and x2.
> * @param x1 the first bound
> * @param x2 the second bound
> * @return erf(x2) - erf(x1)
> * @throws MathException
> */
> public static double erf(double x1, double x2) throws MathException {
> if(x1>x2)
> return erf(x2, x1);
> if(x1==x2)
> return 0.0;
>
> double f1 = erf(x1);
> double f2 = erf(x2);
>
> if(f2 > 0.5)
> if(f1 > 0.5)
> return erfc(x1) - erfc(x2);
> else
> return (0.5-erfc(x2)) + (0.5-f1);
> else
> if(f1 < -0.5)
> if(f2 < -0.5)
> return erfc(-x2) - erfc(-x1);
> else
> return (0.5-erfc(-x1)) + (0.5+f2);
> else
> return f2 - f1;
> }
> {code}
> Further this can be used to improve the NormalDistributionImpl through
> {code:borderStyle=solid}
> @Override
> public double cumulativeProbability(double x0, double x1) throws
> MathException {
> return 0.5 * Erf.erf(
> (x0 - getMean()) / (getStandardDeviation() * sqrt2),
> (x1 - getMean()) / (getStandardDeviation() * sqrt2) );
> }
> {code}
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira