/* * Copyright (c) 2009-2015 * IT-Consulting Stephan Schloepke (http://www.schloepke.de/) * klemm software consulting Mirko Klemm (http://www.klemm-scs.com/) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jbasics.math.strategies; import org.jbasics.math.AlgorithmStrategy; import org.jbasics.math.BigDecimalMathLibrary; import java.math.BigDecimal; import java.math.MathContext; public class GammaIncompleteAlgorithmStrategy implements AlgorithmStrategy<BigDecimal> { private final AlgorithmStrategy<BigDecimal> lnGammaStrategy = new GammaLnLanczosAlgorithmStrategy(LanczosCoefficients.LAN_COEF15); @Override public BigDecimal calculate(final MathContext mc, final BigDecimal guess, final BigDecimal... xn) { final BigDecimal x = xn[0]; final BigDecimal alpha = xn[1]; if (x.signum() == 0) { return BigDecimal.ZERO; } if (x.signum() < 0 || alpha.signum() <= 0) { throw new IllegalArgumentException("Arguments out of bounds"); } final BigDecimal factor = BigDecimalMathLibrary.exp( BigDecimalMathLibrary.ln(x).valueToPrecision(mc).multiply(alpha, mc).subtract(x) .subtract(this.lnGammaStrategy.calculate(mc, null, alpha))).valueToPrecision(mc); if (x.compareTo(BigDecimal.ONE.add(alpha)) < 0) { return GammaIncompleteAlgorithmStrategy.seriesExpansion(x, alpha, factor, mc); } else { return GammaIncompleteAlgorithmStrategy.continuedFraction(x, alpha, factor, mc); } } private static BigDecimal seriesExpansion(final BigDecimal x, final BigDecimal alpha, final BigDecimal factor, final MathContext mc) { // series expansion final BigDecimal lowestTerm = BigDecimal.ONE.scaleByPowerOfTen(-mc.getPrecision()); BigDecimal gin = BigDecimal.ONE; BigDecimal term = BigDecimal.ONE; BigDecimal rn = alpha; do { rn = rn.add(BigDecimal.ONE); term = term.multiply(x.divide(rn, mc), mc); gin = gin.add(term); } while (term.compareTo(lowestTerm) >= 0); return gin.multiply(factor.divide(alpha, mc), mc); } private static BigDecimal continuedFraction(final BigDecimal x, final BigDecimal alpha, final BigDecimal factor, final MathContext mc) { final BigDecimal accurate = BigDecimal.ONE.scaleByPowerOfTen(-8); BigDecimal a = BigDecimal.ONE.subtract(alpha); BigDecimal b = a.add(x).add(BigDecimal.ONE); BigDecimal t = BigDecimal.ZERO; BigDecimal h0 = BigDecimal.ONE; BigDecimal h1 = x; BigDecimal h2 = x.add(BigDecimal.ONE); BigDecimal h3 = x.multiply(b, mc); BigDecimal g = h2.divide(h3, mc); while (true) { a = a.add(BigDecimal.ONE); b = b.add(BigDecimalMathLibrary.CONSTANT_TWO); t = t.add(BigDecimal.ONE); final BigDecimal aa = a.multiply(t, mc); final BigDecimal h4 = b.multiply(h2, mc).subtract(aa.multiply(h0, mc), mc); final BigDecimal h5 = b.multiply(h3, mc).subtract(aa.multiply(h1, mc), mc); if (h5.signum() != 0) { final BigDecimal rn = h4.divide(h5, mc); final BigDecimal dif = g.subtract(rn, mc).abs(); if (dif.compareTo(accurate) <= 0) { if (dif.compareTo(accurate.multiply(rn, mc)) <= 0) { return BigDecimal.ONE.subtract(factor.multiply(g, mc), mc); } } g = rn; } h0 = h2; h1 = h3; h2 = h4; h3 = h5; } } }