[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13108948#comment-13108948 ] Phil Steitz commented on MATH-364: -- Thanks for the test patch. Committed in r1173313. Will CLOSE when 3.0 is released. > 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 > > Attachments: Math-364_additional_test.patch, Math-364_patch.patch > > > 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, 1); > 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
[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ 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: * {@code erf(x_crit) < 0.5}, * {@code erf(Math.nextUp(x_crit) > 0.5}, * {@code erfc(x_crit) = 0.5}, and * {@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, 1); > 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
[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13084315#comment-13084315 ] Christian Winter commented on MATH-364: --- The basic idea is to keep the numbers in the calculation small in order to avoid shifting digits out of the floating point register as this would reduce the accuracy of the final result. Straightforward is to make use of erf(double) if f1 and f2 get close to zero, and to use erfc(double) if f1 and f2 get close to +1 or if they get close to -1. Maybe the mixed cases can be handled in an easier way. I will come back with a new suggestion next week. > 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, 1); > 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
[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13083702#comment-13083702 ] Phil Steitz commented on MATH-364: -- I agree it would be good if it is more accurate and I suspect it probably is, but I have not been able to derive justification for that statement myself or find a reference for the supposedly improved algorithm (in the first code segment above). > 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, 1); > 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
[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13083680#comment-13083680 ] Luc Maisonobe commented on MATH-364: I'm not sure I understand. If adding an erfc(x1, x2) method that compute the difference erc(x1)-erfc(x2) accurately, then it seems a good improvement. > 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, 1); > 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
[jira] [Commented] (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13083514#comment-13083514 ] Phil Steitz commented on MATH-364: -- Any comments on this? > 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, 1); > 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
[jira] Commented: (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12975677#action_12975677 ] Phil Steitz commented on MATH-364: -- To maintain the identity erfc(x) = 1 - erf(x) and to top code for values not distinguishable from 0/2, I think erfc should be {code} public static double erfc(double x) throws MathException { if (FastMath.abs(x) > 40) { return x > 0 ? 0 : 2; } final double ret = Gamma.regularizedGammaQ(0.5, x * x, 1.0e-15, 1); return x < 0 ? 2 - ret : ret; } {code} I understand the intent of erf(x1, x2) but am unable to derive myself or find a reference verifying the superior numerics of the implementation above. Can anyone else provide a reference or explain why the impl given is optimal or at least better than erf(x2) = erf(x1)? > 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: 2.2 > > > 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, 1); > 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. - You can reply to this email to add a comment to the issue online.
[jira] Commented: (MATH-364) Make Erf more precise in the tails by providing erfc
[ https://issues.apache.org/jira/browse/MATH-364?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12856429#action_12856429 ] Phil Steitz commented on MATH-364: -- Thanks for the patch! This looks like a good enhancement. Two things would be helpful to get this incorporated into commons math. 1) You need to confirm that you can and are willing to contribute the code inline above under the terms of the Apache Contributor License Agreement (http://www.apache.org/licenses/icla.txt). You don't need to file this at this point, but you are certainly welcome to do so. Just a comment saying you agree to the terms for the code above is fine for now. 2) Unit tests, ideally using reference data. I will eventually do this if no one has time / itch to do it; but it will speed things up if someone adds them. It would be a little easier for us if the new code and unit tests were included in a patch file (see http://commons.apache.org/patches.html) Thanks again for your interest and contribution! > 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: 2.1 >Reporter: Christian Winter >Priority: Minor > > 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, 1); > 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. - If you think it was sent incorrectly contact one of the administrators: https://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira