/*
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;
import org.jquantlib.QL;
import org.jquantlib.math.distributions.GammaFunction;
/**
* @author
*/
public class RegularisedIncompleteBeta {
//
// private fields
//
private final double tolerance_;
private final int maxIterations_;
private static final GammaFunction _gammaFunction = new GammaFunction();
public RegularisedIncompleteBeta(final double tolerance, final int maxIterations){
checkMaxIterations(maxIterations);
tolerance_ = tolerance;
maxIterations_ = maxIterations;
}
public RegularisedIncompleteBeta(){
tolerance_ = 1.0e-16;
maxIterations_ = 100;
}
/*
The implementation of the algorithm was inspired by
"Numerical Recipes in C", 2nd edition,
Press, Teukolsky, Vetterling, Flannery, chapter 6
*/
private double betaContinuedFraction(final double a, final double b, final double x,
final double accuracy, final int maxIteration) {
checkMaxIterations(maxIteration);
double aa, del;
final double qab = a+b;
final double qap = a+1.0;
final double qam = a-1.0;
double c = 1.0;
double d = 1.0-qab*x/qap;
if (Math.abs(d) < Constants.QL_EPSILON)
d = Constants.QL_EPSILON;
d = 1.0/d;
double result = d;
int m, m2;
for (m=1; m<=maxIteration; m++) {
m2=2*m;
aa=m*(b-m)*x/((qam+m2)*(a+m2));
d=1.0+aa*d;
if (Math.abs(d) < Constants.QL_EPSILON) d=Constants.QL_EPSILON;
c=1.0+aa/c;
if (Math.abs(c) < Constants.QL_EPSILON) c=Constants.QL_EPSILON;
d=1.0/d;
result *= d*c;
aa = -(a+m)*(qab+m)*x/((a+m2)*(qap+m2));
d=1.0+aa*d;
if (Math.abs(d) < Constants.QL_EPSILON) d=Constants.QL_EPSILON;
c=1.0+aa/c;
if (Math.abs(c) < Constants.QL_EPSILON) c=Constants.QL_EPSILON;
d=1.0/d;
del=d*c;
result *= del;
if (Math.abs(del-1.0) < accuracy)
return result;
}
throw new ArithmeticException("a or b too big, or maxIteration too small in betacf"); // TODO: message
}
/**
* Regularised incomplete beta function
* @param a
* @param b
* @param x
* @param accuracy
* @param maxIteration
* @return regularised incomplete beta
*/
public double evaluate(final double x,final double a, final double b) {
checkMaxIterations(maxIterations_);
QL.require(a > 0.0 , "a must be greater than zero"); // TODO: message
QL.require(b > 0.0 , "b must be greater than zero"); // TODO: message
if (x == 0.0)
return 0.0;
if (x == 1.0)
return 1.0;
QL.require(x>0.0 && x<1.0 , "x must be in [0,1]"); // TODO: message
final double result = Math.exp(_gammaFunction.logValue(a+b) -
_gammaFunction.logValue(a) - _gammaFunction.logValue(b) +
a*Math.log(x) + b*Math.log(1.0-x));
if (x < (a+1.0)/(a+b+2.0))
return result * betaContinuedFraction(a, b, x, tolerance_, maxIterations_)/a;
return 1.0 - result * betaContinuedFraction(b, a, 1.0-x, tolerance_, maxIterations_)/b;
}
/**
* Checks if maxIterations is >= 1.
* @param maxIterations
* @throws IllegalArgumentException if maxIterations<1
*/
private void checkMaxIterations(final int maxIterations){
QL.require(maxIterations>0 , "Expected maxIterations must be greater 0"); // TODO: message
}
}
Ads help maintain this website.