    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.math3.special;
    018
    019    import org.apache.commons.math3.util.FastMath;
    020
    021    /**
    022     * This is a utility class that provides computation methods related to the
    023     * error functions.
    024     *
    025     * @version $Id: Erf.java 1416643 2012-12-03 19:37:14Z tn $
    026     */
    027    public class Erf {
    028
    029        /**
    030         * The number {@code X_CRIT} is used by {@link #erf(double, double)} internally.
    031         * This number solves {@code erf(x)=0.5} within 1ulp.
    032         * More precisely, the current implementations of
    033         * {@link #erf(double)} and {@link #erfc(double)} satisfy:<br/>
    034         * {@code erf(X_CRIT) < 0.5},<br/>
    035         * {@code erf(Math.nextUp(X_CRIT) > 0.5},<br/>
    036         * {@code erfc(X_CRIT) = 0.5}, and<br/>
    037         * {@code erfc(Math.nextUp(X_CRIT) < 0.5}
    038         */
    039        private static final double X_CRIT = 0.4769362762044697;
    040
    041        /**
    042         * Default constructor.  Prohibit instantiation.
    043         */
    044        private Erf() {}
    045
    046        /**
    047         * Returns the error function.
    048         *
    049         * <p>erf(x) = 2/&radic;&pi; <sub>0</sub>&int;<sup>x</sup> e<sup>-t<sup>2</sup></sup>dt </p>
    050         *
    051         * <p>This implementation computes erf(x) using the
    052         * {@link Gamma#regularizedGammaP(double, double, double, int) regularized gamma function},
    053         * following <a href="http://mathworld.wolfram.com/Erf.html"> Erf</a>, equation (3)</p>
    054         *
    055         * <p>The value returned is always between -1 and 1 (inclusive).
    056         * If {@code abs(x) > 40}, then {@code erf(x)} is indistinguishable from
    057         * either 1 or -1 as a double, so the appropriate extreme value is returned.
    058         * </p>
    059         *
    060         * @param x the value.
    061         * @return the error function erf(x)
    062         * @throws org.apache.commons.math3.exception.MaxCountExceededException
    063         * if the algorithm fails to converge.
    064         * @see Gamma#regularizedGammaP(double, double, double, int)
    065         */
    066        public static double erf(double x) {
    067            if (FastMath.abs(x) > 40) {
    068                return x > 0 ? 1 : -1;
    069            }
    070            final double ret = Gamma.regularizedGammaP(0.5, x * x, 1.0e-15, 10000);
    071            return x < 0 ? -ret : ret;
    072        }
    073
    074        /**
    075         * Returns the complementary error function.
    076         *
    077         * <p>erfc(x) = 2/&radic;&pi; <sub>x</sub>&int;<sup>&infin;</sup> e<sup>-t<sup>2</sup></sup>dt
    078         * <br/>
    079         *    = 1 - {@link #erf(double) erf(x)} </p>
    080         *
    081         * <p>This implementation computes erfc(x) using the
    082         * {@link Gamma#regularizedGammaQ(double, double, double, int) regularized gamma function},
    083         * following <a href="http://mathworld.wolfram.com/Erf.html"> Erf</a>, equation (3).</p>
    084         *
    085         * <p>The value returned is always between 0 and 2 (inclusive).
    086         * If {@code abs(x) > 40}, then {@code erf(x)} is indistinguishable from
    087         * either 0 or 2 as a double, so the appropriate extreme value is returned.
    088         * </p>
    089         *
    090         * @param x the value
    091         * @return the complementary error function erfc(x)
    092         * @throws org.apache.commons.math3.exception.MaxCountExceededException
    093         * if the algorithm fails to converge.
    094         * @see Gamma#regularizedGammaQ(double, double, double, int)
    095         * @since 2.2
    096         */
    097        public static double erfc(double x) {
    098            if (FastMath.abs(x) > 40) {
    099                return x > 0 ? 0 : 2;
    100            }
    101            final double ret = Gamma.regularizedGammaQ(0.5, x * x, 1.0e-15, 10000);
    102            return x < 0 ? 2 - ret : ret;
    103        }
    104
    105        /**
    106         * Returns the difference between erf(x1) and erf(x2).
    107         *
    108         * The implementation uses either erf(double) or erfc(double)
    109         * depending on which provides the most precise result.
    110         *
    111         * @param x1 the first value
    112         * @param x2 the second value
    113         * @return erf(x2) - erf(x1)
    114         */
    115        public static double erf(double x1, double x2) {
    116            if(x1 > x2) {
    117                return -erf(x2, x1);
    118            }
    119
    120            return
    121            x1 < -X_CRIT ?
    122                x2 < 0.0 ?
    123                    erfc(-x2) - erfc(-x1) :
    124                    erf(x2) - erf(x1) :
    125                x2 > X_CRIT && x1 > 0.0 ?
    126                    erfc(x1) - erfc(x2) :
    127                    erf(x2) - erf(x1);
    128        }
    129    }
    130