Java tutorial
/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package geogebra.kernel; import geogebra.kernel.arithmetic.NumberValue; import java.math.BigDecimal; import java.math.BigInteger; import org.apache.commons.math.special.Gamma; //from http://www.javajungle.de/math/primes/PrimeNumberSieve.html //import de.luschny.math.primes.PrimeSieve; //import de.luschny.math.primes.IPrimeIteration; /** * Computes Binomial[a, b] * @author Michael Borcherds 2007-10-09 * @version */ public class AlgoBinomial extends AlgoTwoNumFunction { private static final long serialVersionUID = 1L; // private static double POSITIVE_INFINITY=1f/0f; // private static double LARGEST_INTEGER=9007199254740992d; // private static double factorialtable[]=new double[101]; // initialised to zero; /* public static BigInteger binomial(int n, int k) { if (0 > k || k > n) { throw new ArithmeticException( "Binomial: 0 <= k and k <= n required, but n was " + n + " and k was " + k ); } if(k > n / 2) { k = n - k ; } int rootN = (int) Math.floor(Math.sqrt(n)); BigInteger binom = BigInteger.ONE ; IPrimeIteration pIter = new PrimeSieve(n).getIteration(); for (int prime : pIter) // equivalent to a nextPrime() function. { // prime runs through the prime numbers 1 < prime <= n if(prime > n - k) { binom = binom.multiply(BigInteger.valueOf(prime)); continue; } if(prime > n / 2) { continue; } if(prime > rootN) { if(n % prime < k % prime) { binom = binom.multiply(BigInteger.valueOf(prime)); } continue; } int exp = 0, r = 0, N = n, K = k; while (N > 0) { r = (N % prime) < (K % prime + r) ? 1 : 0; exp += r; N /= prime; K /= prime; } if (exp > 0) { binom = binom.multiply(BigInteger.valueOf(prime).pow(exp)); } } return binom; }*/ private double Binom(double n, double r) { double INFINITY = Double.POSITIVE_INFINITY; try { if (n == 0d && r == 0d) return 1d; if (r > n / 2) r = n - r; if (n < 1d || r < 0d || n < r) return 0d; if (Math.floor(n) != n || Math.floor(r) != r) return 0d; double ncr = BinomLog(n, r); if (ncr == INFINITY) return INFINITY; // check to stop needless slow calculations // BinomLog is not exact for some values // (determined by trial and error) if (n <= 37) return ncr; //if (r<2.8+Math.exp((250-n)/100) && n<59000) return ncr; // BinomBig is more accurate but slower // (but cannot be exact if the answer has more than about 16 significant digits) return BinomBig(n, r); } catch (Exception e) { return INFINITY; } } private double BinomBig(double n, double r) { if (r > n / 2) r = n - r; BigInteger ncr = BigInteger.ONE, dd = BigInteger.ONE, nn, rr; // nn=BigInteger.valueOf((long)n); // rr=BigInteger.valueOf((long)r); // need a long-winded conversion in case n>10^18 Double nnn = new Double(n); Double rrr = new Double(r); nn = (new BigDecimal(nnn.toString())).toBigInteger(); rr = (new BigDecimal(rrr.toString())).toBigInteger(); while (dd.compareTo(rr) <= 0) { ncr = ncr.multiply(nn); ncr = ncr.divide(dd); // dd is guaranteed to divide exactly into ncr here nn = nn.subtract(BigInteger.ONE); dd = dd.add(BigInteger.ONE); } return ncr.doubleValue(); } private double BinomLog(double n, double r) { // exact for n<=37 // also if r<2.8+Math.exp((250-n)/100) && n<59000 // eg Binom2(38,19) is wrong return Math.floor( 0.5 + Math.exp(Gamma.logGamma(n + 1d) - Gamma.logGamma(r + 1) - Gamma.logGamma((n - r) + 1))); } AlgoBinomial(Construction cons, String label, NumberValue a, NumberValue b) { super(cons, label, a, b); } public String getClassName() { return "AlgoBinomial"; } protected final void compute() { if (input[0].isDefined() && input[1].isDefined()) { double nCr = Binom(a.getDouble(), b.getDouble()); num.setValue(nCr); } else num.setUndefined(); } }