BoostErf.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. //  (C) Copyright John Maddock 2006.
  18. //  Use, modification and distribution are subject to the
  19. //  Boost Software License, Version 1.0. (See accompanying file
  20. //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

  21. package org.apache.commons.numbers.gamma;

  22. import org.apache.commons.numbers.core.DD;

  23. /**
  24.  * Implementation of the <a href="http://mathworld.wolfram.com/Erf.html">error function</a> and
  25.  * its inverse.
  26.  *
  27.  * <p>This code has been adapted from the <a href="https://www.boost.org/">Boost</a>
  28.  * {@code c++} implementation {@code <boost/math/special_functions/erf.hpp>}.
  29.  * The erf/erfc functions and their inverses are copyright John Maddock 2006 and subject to
  30.  * the Boost Software License.
  31.  *
  32.  * <p>Additions made to support the erfcx function are original work under the Apache software
  33.  * license.
  34.  *
  35.  * @see
  36.  * <a href="https://www.boost.org/doc/libs/1_77_0/libs/math/doc/html/math_toolkit/sf_erf/error_function.html">
  37.  * Boost C++ Error functions</a>
  38.  */
  39. final class BoostErf {
  40.     /** 1 / sqrt(pi). Used for the scaled complementary error function erfcx. */
  41.     private static final double ONE_OVER_ROOT_PI = 0.5641895835477562869480794515607725858;
  42.     /** Threshold for the scaled complementary error function erfcx
  43.      * where the approximation {@code (1 / sqrt(pi)) / x} can be used. */
  44.     private static final double ERFCX_APPROX = 6.71e7;
  45.     /** Threshold for the erf implementation for |x| where the computation
  46.      * uses {@code erf(x)}; otherwise {@code erfc(x)} is computed. The final result is
  47.      * achieved by suitable application of symmetry. */
  48.     private static final double COMPUTE_ERF = 0.5;
  49.     /** Threshold for the scaled complementary error function erfcx for negative x
  50.      * where {@code 2 * exp(x*x)} will overflow. Value is 26.62873571375149. */
  51.     private static final double ERFCX_NEG_X_MAX = Math.sqrt(Math.log(Double.MAX_VALUE / 2));
  52.     /** Threshold for the scaled complementary error function erfcx for x
  53.      * where {@code exp(x*x) == 1; x <= t}. Value is (1 + 5/16) * 2^-27 = 9.778887033462524E-9.
  54.      * <p>Note: This is used for performance. If set to 0 then the result is computed
  55.      * using expm1(x*x) with the same final result. */
  56.     private static final double EXP_XX_1 = 0x1.5p-27;

  57.     /** Private constructor. */
  58.     private BoostErf() {
  59.         // intentionally empty.
  60.     }

  61.     // Code ported from Boost 1.77.0
  62.     //
  63.     // boost/math/special_functions/erf.hpp
  64.     // boost/math/special_functions/detail/erf_inv.hpp
  65.     //
  66.     // Original code comments, including measured deviations, are preserved.
  67.     //
  68.     // Changes to the Boost implementation:
  69.     // - Update method names to replace underscores with camel case
  70.     // - Explicitly inline the polynomial function evaluation
  71.     //   using Horner's method (https://en.wikipedia.org/wiki/Horner%27s_method)
  72.     // - Support odd function for f(0.0) = -f(-0.0)
  73.     // - Support the scaled complementary error function erfcx
  74.     // Erf:
  75.     // - Change extended precision z*z to compute the square round-off
  76.     //   using Dekker's method
  77.     // - Change extended precision exp(-z*z) to compute using a
  78.     //   round-off addition to the standard exp result (see NUMBERS-177)
  79.     // - Change the erf threshold for z when erf(z)=1 from
  80.     //   z > 5.8f to z > 5.930664
  81.     // - Change the erfc threshold for z when erfc(z)=0 from
  82.     //   z < 28 to z < 27.3
  83.     // - Change rational function approximation for z > 4 to a function
  84.     //   suitable for erfcx (see NUMBERS-177)
  85.     // Inverse erf:
  86.     // - Change inverse erf edge case detection to include NaN
  87.     // - Change edge case detection for integer z
  88.     //
  89.     // Note:
  90.     // Constants using the 'f' suffix are machine
  91.     // representable as a float, e.g.
  92.     // assert 0.0891314744949340820313f == 0.0891314744949340820313;
  93.     // The values are unchanged from the Boost reference.

  94.     /**
  95.      * Returns the complementary error function.
  96.      *
  97.      * @param x the value.
  98.      * @return the complementary error function.
  99.      */
  100.     static double erfc(double x) {
  101.         return erfImp(x, true, false);
  102.     }

  103.     /**
  104.      * Returns the error function.
  105.      *
  106.      * @param x the value.
  107.      * @return the error function.
  108.      */
  109.     static double erf(double x) {
  110.         return erfImp(x, false, false);
  111.     }

  112.     /**
  113.      * 53-bit implementation for the error function.
  114.      *
  115.      * <p>Note: The {@code scaled} flag only applies when
  116.      * {@code z >= 0.5} and {@code invert == true}.
  117.      * This functionality is used to compute erfcx(z) for positive z.
  118.      *
  119.      * @param z Point to evaluate
  120.      * @param invert true to invert the result (for the complementary error function)
  121.      * @param scaled true to compute the scaled complementary error function
  122.      * @return the error function result
  123.      */
  124.     private static double erfImp(double z, boolean invert, boolean scaled) {
  125.         if (Double.isNaN(z)) {
  126.             return Double.NaN;
  127.         }

  128.         if (z < 0) {
  129.             // Here the scaled flag is ignored.
  130.             if (!invert) {
  131.                 return -erfImp(-z, invert, false);
  132.             } else if (z < -0.5) {
  133.                 return 2 - erfImp(-z, invert, false);
  134.             } else {
  135.                 return 1 + erfImp(-z, false, false);
  136.             }
  137.         }

  138.         double result;

  139.         //
  140.         // Big bunch of selection statements now to pick
  141.         // which implementation to use,
  142.         // try to put most likely options first:
  143.         //
  144.         if (z < COMPUTE_ERF) {
  145.             //
  146.             // We're going to calculate erf:
  147.             //
  148.             // Here the scaled flag is ignored.
  149.             if (z < 1e-10) {
  150.                 if (z == 0) {
  151.                     result = z;
  152.                 } else {
  153.                     final double c = 0.003379167095512573896158903121545171688;
  154.                     result = z * 1.125f + z * c;
  155.                 }
  156.             } else {
  157.                 // Maximum Deviation Found:                      1.561e-17
  158.                 // Expected Error Term:                          1.561e-17
  159.                 // Maximum Relative Change in Control Points:    1.155e-04
  160.                 // Max Error found at double precision =         2.961182e-17

  161.                 final double Y = 1.044948577880859375f;
  162.                 final double zz = z * z;
  163.                 double P;
  164.                 P = -0.000322780120964605683831;
  165.                 P =  -0.00772758345802133288487 + P * zz;
  166.                 P =   -0.0509990735146777432841 + P * zz;
  167.                 P =    -0.338165134459360935041 + P * zz;
  168.                 P =    0.0834305892146531832907 + P * zz;
  169.                 double Q;
  170.                 Q = 0.000370900071787748000569;
  171.                 Q =  0.00858571925074406212772 + Q * zz;
  172.                 Q =   0.0875222600142252549554 + Q * zz;
  173.                 Q =    0.455004033050794024546 + Q * zz;
  174.                 Q =                        1.0 + Q * zz;
  175.                 result = z * (Y + P / Q);
  176.             }
  177.         // Note: Boost threshold of 5.8f has been raised to approximately 5.93 (6073 / 1024);
  178.         // threshold of 28 has been lowered to approximately 27.3 (6989/256) where exp(-z*z) = 0.
  179.         } else if (scaled || (invert ? (z < 27.300781f) : (z < 5.9306640625f))) {
  180.             //
  181.             // We'll be calculating erfc:
  182.             //
  183.             // Here the scaled flag is used.
  184.             invert = !invert;
  185.             if (z < 1.5f) {
  186.                 // Maximum Deviation Found:                     3.702e-17
  187.                 // Expected Error Term:                         3.702e-17
  188.                 // Maximum Relative Change in Control Points:   2.845e-04
  189.                 // Max Error found at double precision =        4.841816e-17
  190.                 final double Y = 0.405935764312744140625f;
  191.                 final double zm = z - 0.5;
  192.                 double P;
  193.                 P = 0.00180424538297014223957;
  194.                 P =  0.0195049001251218801359 + P * zm;
  195.                 P =  0.0888900368967884466578 + P * zm;
  196.                 P =   0.191003695796775433986 + P * zm;
  197.                 P =   0.178114665841120341155 + P * zm;
  198.                 P =  -0.098090592216281240205 + P * zm;
  199.                 double Q;
  200.                 Q = 0.337511472483094676155e-5;
  201.                 Q =   0.0113385233577001411017 + Q * zm;
  202.                 Q =     0.12385097467900864233 + Q * zm;
  203.                 Q =    0.578052804889902404909 + Q * zm;
  204.                 Q =     1.42628004845511324508 + Q * zm;
  205.                 Q =     1.84759070983002217845 + Q * zm;
  206.                 Q =                        1.0 + Q * zm;
  207.                 result = Y + P / Q;
  208.                 if (scaled) {
  209.                     result /= z;
  210.                 } else {
  211.                     result *= expmxx(z) / z;
  212.                 }
  213.             } else if (z < 2.5f) {
  214.                 // Max Error found at double precision =        6.599585e-18
  215.                 // Maximum Deviation Found:                     3.909e-18
  216.                 // Expected Error Term:                         3.909e-18
  217.                 // Maximum Relative Change in Control Points:   9.886e-05
  218.                 final double Y = 0.50672817230224609375f;
  219.                 final double zm = z - 1.5;
  220.                 double P;
  221.                 P = 0.000235839115596880717416;
  222.                 P =  0.00323962406290842133584 + P * zm;
  223.                 P =   0.0175679436311802092299 + P * zm;
  224.                 P =     0.04394818964209516296 + P * zm;
  225.                 P =   0.0386540375035707201728 + P * zm;
  226.                 P =  -0.0243500476207698441272 + P * zm;
  227.                 double Q;
  228.                 Q = 0.00410369723978904575884;
  229.                 Q =  0.0563921837420478160373 + Q * zm;
  230.                 Q =   0.325732924782444448493 + Q * zm;
  231.                 Q =   0.982403709157920235114 + Q * zm;
  232.                 Q =    1.53991494948552447182 + Q * zm;
  233.                 Q =                       1.0 + Q * zm;
  234.                 result = Y + P / Q;
  235.                 if (scaled) {
  236.                     result /= z;
  237.                 } else {
  238.                     result *= expmxx(z) / z;
  239.                 }
  240.             // Lowered Boost threshold from 4.5 to 4.0 as this is the limit
  241.             // for the Cody erfc approximation
  242.             } else if (z < 4.0f) {
  243.                 // Maximum Deviation Found:                     1.512e-17
  244.                 // Expected Error Term:                         1.512e-17
  245.                 // Maximum Relative Change in Control Points:   2.222e-04
  246.                 // Max Error found at double precision =        2.062515e-17
  247.                 final double Y = 0.5405750274658203125f;
  248.                 final double zm = z - 3.5;
  249.                 double P;
  250.                 P = 0.113212406648847561139e-4;
  251.                 P = 0.000250269961544794627958 + P * zm;
  252.                 P =  0.00212825620914618649141 + P * zm;
  253.                 P =  0.00840807615555585383007 + P * zm;
  254.                 P =   0.0137384425896355332126 + P * zm;
  255.                 P =  0.00295276716530971662634 + P * zm;
  256.                 double Q;
  257.                 Q = 0.000479411269521714493907;
  258.                 Q =   0.0105982906484876531489 + Q * zm;
  259.                 Q =   0.0958492726301061423444 + Q * zm;
  260.                 Q =    0.442597659481563127003 + Q * zm;
  261.                 Q =     1.04217814166938418171 + Q * zm;
  262.                 Q =                        1.0 + Q * zm;
  263.                 result = Y + P / Q;
  264.                 if (scaled) {
  265.                     result /= z;
  266.                 } else {
  267.                     result *= expmxx(z) / z;
  268.                 }
  269.             } else {
  270.                 // Rational function approximation for erfc(x > 4.0)
  271.                 //
  272.                 // This approximation is not the Boost implementation.
  273.                 // The Boost function is suitable for [4.5 < z < 28].
  274.                 //
  275.                 // This function is suitable for erfcx(z) as it asymptotes
  276.                 // to (1 / sqrt(pi)) / z at large z.
  277.                 //
  278.                 // Taken from "Rational Chebyshev approximations for the error function"
  279.                 // by W. J. Cody, Math. Comp., 1969, PP. 631-638.
  280.                 //
  281.                 // See NUMBERS-177.

  282.                 final double izz = 1 / (z * z);
  283.                 double p;
  284.                 p = 1.63153871373020978498e-2;
  285.                 p = 3.05326634961232344035e-1 + p * izz;
  286.                 p = 3.60344899949804439429e-1 + p * izz;
  287.                 p = 1.25781726111229246204e-1 + p * izz;
  288.                 p = 1.60837851487422766278e-2 + p * izz;
  289.                 p = 6.58749161529837803157e-4 + p * izz;
  290.                 double q;
  291.                 q = 1;
  292.                 q = 2.56852019228982242072e00 + q * izz;
  293.                 q = 1.87295284992346047209e00 + q * izz;
  294.                 q = 5.27905102951428412248e-1 + q * izz;
  295.                 q = 6.05183413124413191178e-2 + q * izz;
  296.                 q = 2.33520497626869185443e-3 + q * izz;

  297.                 result = izz * p / q;
  298.                 result = (ONE_OVER_ROOT_PI - result) / z;

  299.                 if (!scaled) {
  300.                     // exp(-z*z) can be sub-normal so
  301.                     // multiply by any sub-normal after divide by z
  302.                     result *= expmxx(z);
  303.                 }
  304.             }
  305.         } else {
  306.             //
  307.             // Any value of z larger than 27.3 will underflow to zero:
  308.             //
  309.             result = 0;
  310.             invert = !invert;
  311.         }

  312.         if (invert) {
  313.             // Note: If 0.5 <= z < 28 and the scaled flag is true then
  314.             // invert will have been flipped to false and the
  315.             // the result is unchanged as erfcx(z)
  316.             result = 1 - result;
  317.         }

  318.         return result;
  319.     }

  320.     /**
  321.      * Returns the scaled complementary error function.
  322.      * <pre>
  323.      * erfcx(x) = exp(x^2) * erfc(x)
  324.      * </pre>
  325.      *
  326.      * @param x the value.
  327.      * @return the scaled complementary error function.
  328.      */
  329.     static double erfcx(double x) {
  330.         if (Double.isNaN(x)) {
  331.             return Double.NaN;
  332.         }

  333.         // For |z| < 0.5 erfc is computed using erf
  334.         final double ax = Math.abs(x);
  335.         if (ax < COMPUTE_ERF) {
  336.             // Use the erf(x) result.
  337.             // (1 - erf(x)) * exp(x*x)

  338.             final double erfx = erf(x);
  339.             if (ax < EXP_XX_1) {
  340.                 // No exponential required
  341.                 return 1 - erfx;
  342.             }

  343.             // exp(x*x) - exp(x*x) * erf(x)
  344.             // Avoid use of exp(x*x) with expm1:
  345.             // exp(x*x) - 1 - (erf(x) * (exp(x*x) - 1)) - erf(x) + 1

  346.             // Sum small to large: |erf(x)| > expm1(x*x)
  347.             // -erf(x) * expm1(x*x) + expm1(x*x) - erf(x) + 1
  348.             // Negative x: erf(x) < 0, summed terms are positive, no cancellation occurs.
  349.             // Positive x: erf(x) > 0 so cancellation can occur.
  350.             // When terms are ordered by absolute magnitude the magnitude of the next term
  351.             // is above the round-off from adding the previous term to the sum. Thus
  352.             // cancellation is negligible compared to errors in the largest computed term (erf(x)).

  353.             final double em1 = Math.expm1(x * x);
  354.             return -erfx * em1 + em1 - erfx + 1;
  355.         }

  356.         // Handle negative arguments
  357.         if (x < 0) {
  358.             // erfcx(x) = 2*exp(x*x) - erfcx(-x)

  359.             if (x < -ERFCX_NEG_X_MAX) {
  360.                 // Overflow
  361.                 return Double.POSITIVE_INFINITY;
  362.             }

  363.             final double e = expxx(x);
  364.             return e - erfImp(-x, true, true) + e;
  365.         }

  366.         // Approximation for large positive x
  367.         if (x > ERFCX_APPROX) {
  368.             return ONE_OVER_ROOT_PI / x;
  369.         }

  370.         // Compute erfc scaled
  371.         return erfImp(x, true, true);
  372.     }

  373.     /**
  374.      * Returns the inverse complementary error function.
  375.      *
  376.      * @param z Value (in {@code [0, 2]}).
  377.      * @return t such that {@code z = erfc(t)}
  378.      */
  379.     static double erfcInv(double z) {
  380.         //
  381.         // Begin by testing for domain errors, and other special cases:
  382.         //
  383.         if (z < 0 || z > 2 || Double.isNaN(z)) {
  384.             // Argument outside range [0,2] in inverse erfc function
  385.             return Double.NaN;
  386.         }
  387.         // Domain bounds must be detected as the implementation computes NaN.
  388.         // (log(q=0) creates infinity and the rational number is
  389.         // infinity / infinity)
  390.         if (z == (int) z) {
  391.             // z   return
  392.             // 2   -inf
  393.             // 1   0
  394.             // 0   inf
  395.             return z == 1 ? 0 : (1 - z) * Double.POSITIVE_INFINITY;
  396.         }

  397.         //
  398.         // Normalise the input, so it's in the range [0,1], we will
  399.         // negate the result if z is outside that range. This is a simple
  400.         // application of the erfc reflection formula: erfc(-z) = 2 - erfc(z)
  401.         //
  402.         final double p;
  403.         final double q;
  404.         final double s;
  405.         if (z > 1) {
  406.             q = 2 - z;
  407.             p = 1 - q;
  408.             s = -1;
  409.         } else {
  410.             p = 1 - z;
  411.             q = z;
  412.             s = 1;
  413.         }

  414.         //
  415.         // And get the result, negating where required:
  416.         //
  417.         return s * erfInvImp(p, q);
  418.     }

  419.     /**
  420.      * Returns the inverse error function.
  421.      *
  422.      * @param z Value (in {@code [-1, 1]}).
  423.      * @return t such that {@code z = erf(t)}
  424.      */
  425.     static double erfInv(double z) {
  426.         //
  427.         // Begin by testing for domain errors, and other special cases:
  428.         //
  429.         if (z < -1 || z > 1 || Double.isNaN(z)) {
  430.             // Argument outside range [-1, 1] in inverse erf function
  431.             return Double.NaN;
  432.         }
  433.         // Domain bounds must be detected as the implementation computes NaN.
  434.         // (log(q=0) creates infinity and the rational number is
  435.         // infinity / infinity)
  436.         if (z == (int) z) {
  437.             // z   return
  438.             // -1  -inf
  439.             // -0  -0
  440.             // 0   0
  441.             // 1   inf
  442.             return z == 0 ? z : z * Double.POSITIVE_INFINITY;
  443.         }

  444.         //
  445.         // Normalise the input, so it's in the range [0,1], we will
  446.         // negate the result if z is outside that range. This is a simple
  447.         // application of the erf reflection formula: erf(-z) = -erf(z)
  448.         //
  449.         final double p;
  450.         final double q;
  451.         final double s;
  452.         if (z < 0) {
  453.             p = -z;
  454.             q = 1 - p;
  455.             s = -1;
  456.         } else {
  457.             p = z;
  458.             q = 1 - z;
  459.             s = 1;
  460.         }
  461.         //
  462.         // And get the result, negating where required:
  463.         //
  464.         return s * erfInvImp(p, q);
  465.     }

  466.     /**
  467.      * Common implementation for inverse erf and erfc functions.
  468.      *
  469.      * @param p P-value
  470.      * @param q Q-value (1-p)
  471.      * @return the inverse
  472.      */
  473.     private static double erfInvImp(double p, double q) {
  474.         final double result;

  475.         if (p <= 0.5) {
  476.             //
  477.             // Evaluate inverse erf using the rational approximation:
  478.             //
  479.             // x = p(p+10)(Y+R(p))
  480.             //
  481.             // Where Y is a constant, and R(p) is optimised for a low
  482.             // absolute error compared to |Y|.
  483.             //
  484.             // double: Max error found: 2.001849e-18
  485.             // long double: Max error found: 1.017064e-20
  486.             // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
  487.             //
  488.             final float Y = 0.0891314744949340820313f;
  489.             double P;
  490.             P =  -0.00538772965071242932965;
  491.             P =   0.00822687874676915743155 + P * p;
  492.             P =    0.0219878681111168899165 + P * p;
  493.             P =   -0.0365637971411762664006 + P * p;
  494.             P =   -0.0126926147662974029034 + P * p;
  495.             P =    0.0334806625409744615033 + P * p;
  496.             P =  -0.00836874819741736770379 + P * p;
  497.             P = -0.000508781949658280665617 + P * p;
  498.             double Q;
  499.             Q = 0.000886216390456424707504;
  500.             Q = -0.00233393759374190016776 + Q * p;
  501.             Q =   0.0795283687341571680018 + Q * p;
  502.             Q =  -0.0527396382340099713954 + Q * p;
  503.             Q =    -0.71228902341542847553 + Q * p;
  504.             Q =    0.662328840472002992063 + Q * p;
  505.             Q =     1.56221558398423026363 + Q * p;
  506.             Q =    -1.56574558234175846809 + Q * p;
  507.             Q =   -0.970005043303290640362 + Q * p;
  508.             Q =                        1.0 + Q * p;
  509.             final double g = p * (p + 10);
  510.             final double r = P / Q;
  511.             result = g * Y + g * r;
  512.         } else if (q >= 0.25) {
  513.             //
  514.             // Rational approximation for 0.5 > q >= 0.25
  515.             //
  516.             // x = sqrt(-2*log(q)) / (Y + R(q))
  517.             //
  518.             // Where Y is a constant, and R(q) is optimised for a low
  519.             // absolute error compared to Y.
  520.             //
  521.             // double : Max error found: 7.403372e-17
  522.             // long double : Max error found: 6.084616e-20
  523.             // Maximum Deviation Found (error term) 4.811e-20
  524.             //
  525.             final float Y = 2.249481201171875f;
  526.             final double xs = q - 0.25f;
  527.             double P;
  528.             P =  -3.67192254707729348546;
  529.             P =   21.1294655448340526258 + P * xs;
  530.             P =    17.445385985570866523 + P * xs;
  531.             P =  -44.6382324441786960818 + P * xs;
  532.             P =  -18.8510648058714251895 + P * xs;
  533.             P =   17.6447298408374015486 + P * xs;
  534.             P =   8.37050328343119927838 + P * xs;
  535.             P =  0.105264680699391713268 + P * xs;
  536.             P = -0.202433508355938759655 + P * xs;
  537.             double Q;
  538.             Q =  1.72114765761200282724;
  539.             Q = -22.6436933413139721736 + Q * xs;
  540.             Q =  10.8268667355460159008 + Q * xs;
  541.             Q =  48.5609213108739935468 + Q * xs;
  542.             Q = -20.1432634680485188801 + Q * xs;
  543.             Q = -28.6608180499800029974 + Q * xs;
  544.             Q =   3.9713437953343869095 + Q * xs;
  545.             Q =  6.24264124854247537712 + Q * xs;
  546.             Q =                     1.0 + Q * xs;
  547.             final double g = Math.sqrt(-2 * Math.log(q));
  548.             final double r = P / Q;
  549.             result = g / (Y + r);
  550.         } else {
  551.             //
  552.             // For q < 0.25 we have a series of rational approximations all
  553.             // of the general form:
  554.             //
  555.             // let: x = sqrt(-log(q))
  556.             //
  557.             // Then the result is given by:
  558.             //
  559.             // x(Y+R(x-B))
  560.             //
  561.             // where Y is a constant, B is the lowest value of x for which
  562.             // the approximation is valid, and R(x-B) is optimised for a low
  563.             // absolute error compared to Y.
  564.             //
  565.             // Note that almost all code will really go through the first
  566.             // or maybe second approximation. After than we're dealing with very
  567.             // small input values indeed.
  568.             //
  569.             // Limit for a double: Math.sqrt(-Math.log(Double.MIN_VALUE)) = 27.28...
  570.             // Branches for x >= 44 (supporting 80 and 128 bit long double) have been removed.
  571.             final double x = Math.sqrt(-Math.log(q));
  572.             if (x < 3) {
  573.                 // Max error found: 1.089051e-20
  574.                 final float Y = 0.807220458984375f;
  575.                 final double xs = x - 1.125f;
  576.                 double P;
  577.                 P = -0.681149956853776992068e-9;
  578.                 P =  0.285225331782217055858e-7 + P * xs;
  579.                 P = -0.679465575181126350155e-6 + P * xs;
  580.                 P =   0.00214558995388805277169 + P * xs;
  581.                 P =    0.0290157910005329060432 + P * xs;
  582.                 P =     0.142869534408157156766 + P * xs;
  583.                 P =     0.337785538912035898924 + P * xs;
  584.                 P =     0.387079738972604337464 + P * xs;
  585.                 P =     0.117030156341995252019 + P * xs;
  586.                 P =    -0.163794047193317060787 + P * xs;
  587.                 P =    -0.131102781679951906451 + P * xs;
  588.                 double Q;
  589.                 Q =  0.01105924229346489121;
  590.                 Q = 0.152264338295331783612 + Q * xs;
  591.                 Q = 0.848854343457902036425 + Q * xs;
  592.                 Q =  2.59301921623620271374 + Q * xs;
  593.                 Q =  4.77846592945843778382 + Q * xs;
  594.                 Q =  5.38168345707006855425 + Q * xs;
  595.                 Q =  3.46625407242567245975 + Q * xs;
  596.                 Q =                     1.0 + Q * xs;
  597.                 final double R = P / Q;
  598.                 result = Y * x + R * x;
  599.             } else if (x < 6) {
  600.                 // Max error found: 8.389174e-21
  601.                 final float Y = 0.93995571136474609375f;
  602.                 final double xs = x - 3;
  603.                 double P;
  604.                 P = 0.266339227425782031962e-11;
  605.                 P = -0.230404776911882601748e-9 + P * xs;
  606.                 P =  0.460469890584317994083e-5 + P * xs;
  607.                 P =  0.000157544617424960554631 + P * xs;
  608.                 P =   0.00187123492819559223345 + P * xs;
  609.                 P =   0.00950804701325919603619 + P * xs;
  610.                 P =    0.0185573306514231072324 + P * xs;
  611.                 P =  -0.00222426529213447927281 + P * xs;
  612.                 P =   -0.0350353787183177984712 + P * xs;
  613.                 double Q;
  614.                 Q = 0.764675292302794483503e-4;
  615.                 Q =  0.00263861676657015992959 + Q * xs;
  616.                 Q =   0.0341589143670947727934 + Q * xs;
  617.                 Q =    0.220091105764131249824 + Q * xs;
  618.                 Q =    0.762059164553623404043 + Q * xs;
  619.                 Q =      1.3653349817554063097 + Q * xs;
  620.                 Q =                        1.0 + Q * xs;
  621.                 final double R = P / Q;
  622.                 result = Y * x + R * x;
  623.             } else if (x < 18) {
  624.                 // Max error found: 1.481312e-19
  625.                 final float Y = 0.98362827301025390625f;
  626.                 final double xs = x - 6;
  627.                 double P;
  628.                 P =   0.99055709973310326855e-16;
  629.                 P = -0.281128735628831791805e-13 + P * xs;
  630.                 P =   0.462596163522878599135e-8 + P * xs;
  631.                 P =   0.449696789927706453732e-6 + P * xs;
  632.                 P =   0.149624783758342370182e-4 + P * xs;
  633.                 P =   0.000209386317487588078668 + P * xs;
  634.                 P =    0.00105628862152492910091 + P * xs;
  635.                 P =   -0.00112951438745580278863 + P * xs;
  636.                 P =    -0.0167431005076633737133 + P * xs;
  637.                 double Q;
  638.                 Q = 0.282243172016108031869e-6;
  639.                 Q = 0.275335474764726041141e-4 + Q * xs;
  640.                 Q = 0.000964011807005165528527 + Q * xs;
  641.                 Q =   0.0160746087093676504695 + Q * xs;
  642.                 Q =    0.138151865749083321638 + Q * xs;
  643.                 Q =    0.591429344886417493481 + Q * xs;
  644.                 Q =                        1.0 + Q * xs;
  645.                 final double R = P / Q;
  646.                 result = Y * x + R * x;
  647.             } else {
  648.                 // x < 44
  649.                 // Max error found: 5.697761e-20
  650.                 final float Y = 0.99714565277099609375f;
  651.                 final double xs = x - 18;
  652.                 double P;
  653.                 P = -0.116765012397184275695e-17;
  654.                 P =  0.145596286718675035587e-11 + P * xs;
  655.                 P =   0.411632831190944208473e-9 + P * xs;
  656.                 P =   0.396341011304801168516e-7 + P * xs;
  657.                 P =   0.162397777342510920873e-5 + P * xs;
  658.                 P =   0.254723037413027451751e-4 + P * xs;
  659.                 P =  -0.779190719229053954292e-5 + P * xs;
  660.                 P =    -0.0024978212791898131227 + P * xs;
  661.                 double Q;
  662.                 Q = 0.509761276599778486139e-9;
  663.                 Q = 0.144437756628144157666e-6 + Q * xs;
  664.                 Q = 0.145007359818232637924e-4 + Q * xs;
  665.                 Q = 0.000690538265622684595676 + Q * xs;
  666.                 Q =   0.0169410838120975906478 + Q * xs;
  667.                 Q =    0.207123112214422517181 + Q * xs;
  668.                 Q =                        1.0 + Q * xs;
  669.                 final double R = P / Q;
  670.                 result = Y * x + R * x;
  671.             }
  672.         }
  673.         return result;
  674.     }

  675.     /**
  676.      * Compute {@code exp(x*x)} with high accuracy. This is performed using
  677.      * information in the round-off from {@code x*x}.
  678.      *
  679.      * <p>This is accurate at large x to 1 ulp.
  680.      *
  681.      * <p>At small x the accuracy cannot be improved over using exp(x*x).
  682.      * This occurs at {@code x <= 1}.
  683.      *
  684.      * <p>Warning: This has no checks for overflow. The method is never called
  685.      * when {@code x*x > log(MAX_VALUE/2)}.
  686.      *
  687.      * @param x Value
  688.      * @return exp(x*x)
  689.      */
  690.     static double expxx(double x) {
  691.         // Note: If exp(a) overflows this can create NaN if the
  692.         // round-off b is negative or zero:
  693.         // exp(a) * exp1m(b) + exp(a)
  694.         // inf * 0 + inf   or   inf * -b  + inf
  695.         final DD x2 = DD.ofSquare(x);
  696.         return expxx(x2.hi(), x2.lo());
  697.     }

  698.     /**
  699.      * Compute {@code exp(-x*x)} with high accuracy. This is performed using
  700.      * information in the round-off from {@code x*x}.
  701.      *
  702.      * <p>This is accurate at large x to 1 ulp until exp(-x*x) is close to
  703.      * sub-normal. For very small exp(-x*x) the adjustment is sub-normal and
  704.      * bits can be lost in the adjustment for a max observed error of {@code < 2} ulp.
  705.      *
  706.      * <p>At small x the accuracy cannot be improved over using exp(-x*x).
  707.      * This occurs at {@code x <= 1}.
  708.      *
  709.      * @param x Value
  710.      * @return exp(-x*x)
  711.      */
  712.     static double expmxx(double x) {
  713.         final DD x2 = DD.ofSquare(x);
  714.         return expxx(-x2.hi(), -x2.lo());
  715.     }

  716.     /**
  717.      * Compute {@code exp(a+b)} with high accuracy assuming {@code a+b = a}.
  718.      *
  719.      * <p>This is accurate at large positive a to 1 ulp. If a is negative and exp(a) is
  720.      * close to sub-normal a bit of precision may be lost when adjusting result
  721.      * as the adjustment is sub-normal (max observed error {@code < 2} ulp).
  722.      * For the use case of multiplication of a number less than 1 by exp(-x*x), a = -x*x,
  723.      * the result will be sub-normal and the rounding error is lost.
  724.      *
  725.      * <p>At small |a| the accuracy cannot be improved over using exp(a) as the
  726.      * round-off is too small to create terms that can adjust the standard result by
  727.      * more than 0.5 ulp. This occurs at {@code |a| <= 1}.
  728.      *
  729.      * @param a High bits of a split number
  730.      * @param b Low bits of a split number
  731.      * @return exp(a+b)
  732.      */
  733.     private static double expxx(double a, double b) {
  734.         // exp(a+b) = exp(a) * exp(b)
  735.         //          = exp(a) * (exp(b) - 1) + exp(a)
  736.         // Assuming:
  737.         // 1. -746 < a < 710 for no under/overflow of exp(a)
  738.         // 2. a+b = a
  739.         // As b -> 0 then exp(b) -> 1; expm1(b) -> b
  740.         // The round-off b is limited to ~ 0.5 * ulp(746) ~ 5.68e-14
  741.         // and we can use an approximation for expm1 (x/1! + x^2/2! + ...)
  742.         // The second term is required for the expm1 result but the
  743.         // bits are not significant to change the following sum with exp(a)

  744.         final double ea = Math.exp(a);
  745.         // b ~ expm1(b)
  746.         return ea * b + ea;
  747.     }
  748. }