You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/11/30 11:30:12 UTC
[commons-numbers] branch master updated: Add Commons Numbers 1.0 implementation to ErfPerformance benchmark
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
The following commit(s) were added to refs/heads/master by this push:
new 29388f2 Add Commons Numbers 1.0 implementation to ErfPerformance benchmark
29388f2 is described below
commit 29388f2a26621539891ef6e2068919ca77fb5cb6
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Nov 30 11:30:01 2021 +0000
Add Commons Numbers 1.0 implementation to ErfPerformance benchmark
Previously the code called RegularizedGamma.P or Q. Since these have
been updated the 1.0 version has been preserved for a reference
benchmark.
---
.../numbers/examples/jmh/gamma/ErfPerformance.java | 167 ++++++++++++++++++++-
1 file changed, 166 insertions(+), 1 deletion(-)
diff --git a/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/gamma/ErfPerformance.java b/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/gamma/ErfPerformance.java
index 07726c7..3df24b7 100644
--- a/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/gamma/ErfPerformance.java
+++ b/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/gamma/ErfPerformance.java
@@ -25,11 +25,12 @@ import java.util.function.DoubleUnaryOperator;
import java.util.function.Supplier;
import java.util.stream.DoubleStream;
import org.apache.commons.numbers.core.Precision;
+import org.apache.commons.numbers.fraction.ContinuedFraction;
import org.apache.commons.numbers.gamma.Erf;
import org.apache.commons.numbers.gamma.Erfc;
import org.apache.commons.numbers.gamma.InverseErf;
import org.apache.commons.numbers.gamma.InverseErfc;
-import org.apache.commons.numbers.gamma.RegularizedGamma;
+import org.apache.commons.numbers.gamma.LogGamma;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -622,6 +623,170 @@ public class ErfPerformance {
}
/**
+ * <a href="http://mathworld.wolfram.com/RegularizedGammaFunction.html">
+ * Regularized Gamma functions</a>.
+ *
+ * <p>This is the Commons Numbers 1.0 implementation. Later versions of
+ * RegularizedGamma changed to compute using more than the continued fraction
+ * representation (Q) or lower gamma series representation (P).
+ *
+ * <p>The ContinuedFraction and LogGamma class use the current version
+ * and are not preserved from Commons Numbers 1.0.
+ */
+ private static final class RegularizedGamma {
+ /** Private constructor. */
+ private RegularizedGamma() {
+ // intentionally empty.
+ }
+
+ /**
+ * \( P(a, x) \) <a href="http://mathworld.wolfram.com/RegularizedGammaFunction.html">
+ * regularized Gamma function</a>.
+ *
+ * Class is immutable.
+ */
+ static final class P {
+ /** Prevent instantiation. */
+ private P() {}
+
+ /**
+ * Computes the regularized gamma function \( P(a, x) \).
+ *
+ * The implementation of this method is based on:
+ * <ul>
+ * <li>
+ * <a href="http://mathworld.wolfram.com/RegularizedGammaFunction.html">
+ * Regularized Gamma Function</a>, equation (1)
+ * </li>
+ * <li>
+ * <a href="http://mathworld.wolfram.com/IncompleteGammaFunction.html">
+ * Incomplete Gamma Function</a>, equation (4).
+ * </li>
+ * <li>
+ * <a href="http://mathworld.wolfram.com/ConfluentHypergeometricFunctionoftheFirstKind.html">
+ * Confluent Hypergeometric Function of the First Kind</a>, equation (1).
+ * </li>
+ * </ul>
+ *
+ * @param a Argument.
+ * @param x Argument.
+ * @param epsilon Tolerance in continued fraction evaluation.
+ * @param maxIterations Maximum number of iterations in continued fraction evaluation.
+ * @return \( P(a, x) \).
+ * @throws ArithmeticException if the continued fraction fails to converge.
+ */
+ static double value(double a,
+ double x,
+ double epsilon,
+ int maxIterations) {
+ if (Double.isNaN(a) ||
+ Double.isNaN(x) ||
+ a <= 0 ||
+ x < 0) {
+ return Double.NaN;
+ } else if (x == 0) {
+ return 0;
+ } else if (x >= a + 1) {
+ // Q should converge faster in this case.
+ return 1 - RegularizedGamma.Q.value(a, x, epsilon, maxIterations);
+ } else {
+ // Series.
+ double n = 0; // current element index
+ double an = 1 / a; // n-th element in the series
+ double sum = an; // partial sum
+ while (Math.abs(an / sum) > epsilon &&
+ n < maxIterations &&
+ sum < Double.POSITIVE_INFINITY) {
+ // compute next element in the series
+ n += 1;
+ an *= x / (a + n);
+
+ // update partial sum
+ sum += an;
+ }
+ if (n >= maxIterations) {
+ throw new ArithmeticException("Max iterations exceeded: " + maxIterations);
+ } else if (Double.isInfinite(sum)) {
+ return 1;
+ } else {
+ // Ensure result is in the range [0, 1]
+ final double result = Math.exp(-x + (a * Math.log(x)) - LogGamma.value(a)) * sum;
+ return result > 1.0 ? 1.0 : result;
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates the \( Q(a, x) \equiv 1 - P(a, x) \) <a href="http://mathworld.wolfram.com/RegularizedGammaFunction.html">
+ * regularized Gamma function</a>.
+ *
+ * Class is immutable.
+ */
+ static final class Q {
+ /** Prevent instantiation. */
+ private Q() {}
+
+ /**
+ * Computes the regularized gamma function \( Q(a, x) = 1 - P(a, x) \).
+ *
+ * The implementation of this method is based on:
+ * <ul>
+ * <li>
+ * <a href="http://mathworld.wolfram.com/RegularizedGammaFunction.html">
+ * Regularized Gamma Function</a>, equation (1).
+ * </li>
+ * <li>
+ * <a href="http://functions.wolfram.com/GammaBetaErf/GammaRegularized/10/0003/">
+ * Regularized incomplete gamma function: Continued fraction representations
+ * (formula 06.08.10.0003)</a>
+ * </li>
+ * </ul>
+ *
+ * @param a Argument.
+ * @param x Argument.
+ * @param epsilon Tolerance in continued fraction evaluation.
+ * @param maxIterations Maximum number of iterations in continued fraction evaluation.
+ * @throws ArithmeticException if the continued fraction fails to converge.
+ * @return \( Q(a, x) \).
+ */
+ static double value(final double a,
+ double x,
+ double epsilon,
+ int maxIterations) {
+ if (Double.isNaN(a) ||
+ Double.isNaN(x) ||
+ a <= 0 ||
+ x < 0) {
+ return Double.NaN;
+ } else if (x == 0) {
+ return 1;
+ } else if (x < a + 1) {
+ // P should converge faster in this case.
+ return 1 - RegularizedGamma.P.value(a, x, epsilon, maxIterations);
+ } else {
+ final ContinuedFraction cf = new ContinuedFraction() {
+ /** {@inheritDoc} */
+ @Override
+ protected double getA(int n, double x) {
+ return n * (a - n);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected double getB(int n, double x) {
+ return ((2 * n) + 1) - a + x;
+ }
+ };
+
+ return Math.exp(-x + (a * Math.log(x)) - LogGamma.value(a)) /
+ cf.evaluate(x, epsilon, maxIterations);
+ }
+ }
+ }
+ }
+
+ /**
* Assert the values are equal to the given epsilon, else throw an AssertionError.
*
* @param x the x