/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.math.special; import org.apache.commons.math.util.ContinuedFraction; import org.apache.commons.math.util.FastMath; /** * This is a utility class that provides computation methods related to the * Beta family of functions. * * @version $Id: Beta.java 1131229 2011-06-03 20:49:25Z luc $ */ public class Beta { /** Maximum allowed numerical error. */ private static final double DEFAULT_EPSILON = 10e-15; /** * Default constructor. Prohibit instantiation. */ private Beta() {} /** * Returns the * <a href="http://mathworld.wolfram.com/RegularizedBetaFunction.html"> * regularized beta function</a> I(x, a, b). * * @param x Value. * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @return the regularized beta function I(x, a, b). * @throws org.apache.commons.math.exception.MaxCountExceededException * if the algorithm fails to converge. */ public static double regularizedBeta(double x, double a, double b) { return regularizedBeta(x, a, b, DEFAULT_EPSILON, Integer.MAX_VALUE); } /** * Returns the * <a href="http://mathworld.wolfram.com/RegularizedBetaFunction.html"> * regularized beta function</a> I(x, a, b). * * @param x Value. * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @param epsilon When the absolute value of the nth item in the * series is less than epsilon the approximation ceases to calculate * further elements in the series. * @return the regularized beta function I(x, a, b) * @throws org.apache.commons.math.exception.MaxCountExceededException * if the algorithm fails to converge. */ public static double regularizedBeta(double x, double a, double b, double epsilon) { return regularizedBeta(x, a, b, epsilon, Integer.MAX_VALUE); } /** * Returns the regularized beta function I(x, a, b). * * @param x the value. * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @param maxIterations Maximum number of "iterations" to complete. * @return the regularized beta function I(x, a, b) * @throws org.apache.commons.math.exception.MaxCountExceededException * if the algorithm fails to converge. */ public static double regularizedBeta(double x, double a, double b, int maxIterations) { return regularizedBeta(x, a, b, DEFAULT_EPSILON, maxIterations); } /** * Returns the regularized beta function I(x, a, b). * * The implementation of this method is based on: * <ul> * <li> * <a href="http://mathworld.wolfram.com/RegularizedBetaFunction.html"> * Regularized Beta Function</a>.</li> * <li> * <a href="http://functions.wolfram.com/06.21.10.0001.01"> * Regularized Beta Function</a>.</li> * </ul> * * @param x the value. * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @param epsilon When the absolute value of the nth item in the * series is less than epsilon the approximation ceases to calculate * further elements in the series. * @param maxIterations Maximum number of "iterations" to complete. * @return the regularized beta function I(x, a, b) * @throws org.apache.commons.math.exception.MaxCountExceededException * if the algorithm fails to converge. */ public static double regularizedBeta(double x, final double a, final double b, double epsilon, int maxIterations) { double ret; if (Double.isNaN(x) || Double.isNaN(a) || Double.isNaN(b) || x < 0 || x > 1 || a <= 0.0 || b <= 0.0) { ret = Double.NaN; } else if (x > (a + 1.0) / (a + b + 2.0)) { ret = 1.0 - regularizedBeta(1.0 - x, b, a, epsilon, maxIterations); } else { ContinuedFraction fraction = new ContinuedFraction() { @Override protected double getB(int n, double x) { double ret; double m; if (n % 2 == 0) { // even m = n / 2.0; ret = (m * (b - m) * x) / ((a + (2 * m) - 1) * (a + (2 * m))); } else { m = (n - 1.0) / 2.0; ret = -((a + m) * (a + b + m) * x) / ((a + (2 * m)) * (a + (2 * m) + 1.0)); } return ret; } @Override protected double getA(int n, double x) { return 1.0; } }; ret = FastMath.exp((a * FastMath.log(x)) + (b * FastMath.log(1.0 - x)) - FastMath.log(a) - logBeta(a, b, epsilon, maxIterations)) * 1.0 / fraction.evaluate(x, epsilon, maxIterations); } return ret; } /** * Returns the natural logarithm of the beta function B(a, b). * * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @return log(B(a, b)). */ public static double logBeta(double a, double b) { return logBeta(a, b, DEFAULT_EPSILON, Integer.MAX_VALUE); } /** * Returns the natural logarithm of the beta function B(a, b). * * The implementation of this method is based on: * <ul> * <li><a href="http://mathworld.wolfram.com/BetaFunction.html"> * Beta Function</a>, equation (1).</li> * </ul> * * @param a Parameter {@code a}. * @param b Parameter {@code b}. * @param epsilon When the absolute value of the nth item in the * series is less than epsilon the approximation ceases to calculate * further elements in the series. * @param maxIterations Maximum number of "iterations" to complete. * @return log(B(a, b)). */ public static double logBeta(double a, double b, double epsilon, int maxIterations) { double ret; if (Double.isNaN(a) || Double.isNaN(b) || a <= 0.0 || b <= 0.0) { ret = Double.NaN; } else { ret = Gamma.logGamma(a) + Gamma.logGamma(b) - Gamma.logGamma(a + b); } return ret; } }