/*
Copyright (C) 2008 Richard Gomes
This source code is release under the BSD License.
This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/
JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/
package org.jquantlib.math.distributions;
import org.jquantlib.QL;
import org.jquantlib.math.Constants;
/**
* In mathematics, the gamma function is defined by a definite integral.
* The incomplete gamma function is defined as an integral function of
* the same integrand.
*
* The incomplete Gamma Function P(a,x) is monotonic and (for a greater than one or so)
* rises from "near-zero" to "near-unity" in a range of x centered on about a-1 and of
* width about sqr(a).
*
* @see Incomplete Gamma Function
* @see Incomplete Gamma Function, Numerical Recipes in C, p. 216.
*
* @author Richard Gomes
* @author Dominik Holenstein
*/
public class IncompleteGamma {
private static final String ACCURACY_NOT_REACHED = "accuracy not reached";
//
// computes the incomplete Gamma Function
//
public double incompleteGammaFunction(final double a, final double x, final double accuracy, final int maxIteration) {
QL.require(a > 0.0 , "non-positive a is not allowed"); // TODO: message
QL.require(x >= 0.0 , "negative x non allowed"); // TODO: message
if (x < (a+1.0))
// Use the series representation
return incompleteGammaFunctionSeriesRepr(a, x, accuracy, maxIteration);
else
// Use the continued fraction representation
return 1.0-incompleteGammaFunctionContinuedFractionRepr(a, x, accuracy, maxIteration);
}
/**
* Computes the incomplete Gamma function by using the series
* representation.
*
* @param a
* @param x
* @param accuracy
* @param maxIteration
* @return incomplete Gamma by using the series representation
*/
private double incompleteGammaFunctionSeriesRepr(final double a, final double x, final double accuracy, final int maxIteration) {
if (x==0.0) return 0.0;
/*@Real*/ final double gln = new GammaFunction().logValue(a);
/*@Real*/ double ap=a;
/*@Real*/ double del=1.0/a;
/*@Real*/ double sum=del;
for (int n=1; n<=maxIteration; n++) {
++ap;
del *= x/ap;
sum += del;
if (Math.abs(del) < Math.abs(sum)*accuracy)
return sum*Math.exp(-x+a*Math.log(x)-gln);
}
throw new ArithmeticException(ACCURACY_NOT_REACHED);
}
/**
* Computes the incomplete Gamma function by using the continued fraction representation.
* @param a
* @param x
* @param accuracy
* @param maxIteration
* @return incomplete Gamma by using the continued fraction representation
*/
public double incompleteGammaFunctionContinuedFractionRepr(final double a, final double x, final double accuracy, final int maxIteration) {
double an, b, c, d;
double del;
double h;
final double gln = new GammaFunction().logValue(a);
b=x+1.0-a;
c=1.0/Constants.QL_EPSILON;
d=1.0/b;
h=d;
for (int i=1; i<=maxIteration; i++) {
an = -i*(i-a);
b += 2.0;
d=an*d+b;
if (Math.abs(d) < Constants.QL_EPSILON) {
d=Constants.QL_EPSILON;
}
c=b+an/c;
if (Math.abs(c) < Constants.QL_EPSILON) {
c=Constants.QL_EPSILON;
}
d=1.0/d;
del=d*c;
h *= del;
if (Math.abs(del-1.0) < accuracy)
return Math.exp(-x+a*Math.log(x)-gln)*h;
}
throw new ArithmeticException(ACCURACY_NOT_REACHED);
}
}
Ads help maintain this website.