mirror of https://github.com/jlizier/jidt
651 lines
20 KiB
Java
Executable File
651 lines
20 KiB
Java
Executable File
/*
|
|
* Java Information Dynamics Toolkit (JIDT)
|
|
* Copyright (C) 2012, Joseph T. Lizier
|
|
*
|
|
* 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, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package infodynamics.utils;
|
|
|
|
import infodynamics.utils.commonsmath3.special.Gamma;
|
|
|
|
/**
|
|
* This class implements a number of static
|
|
* methods for mathematical functions.
|
|
*
|
|
* @author Joseph Lizier (<a href="joseph.lizier at gmail.com">email</a>,
|
|
* <a href="http://lizier.me/joseph/">www</a>)
|
|
*/
|
|
public class MathsUtils {
|
|
|
|
private static final double EULER_MASCHERONI_CONSTANT = 0.5772156;
|
|
|
|
private static int highestDigammaArgCalced = 0;
|
|
private static final int NUM_STORED_DIGAMMAS = 10000; // commons.math to handle beyond this
|
|
private static double[] storedDigammas = new double[0];
|
|
|
|
/**
|
|
* Returns the integer result of base^power
|
|
*
|
|
* @param base base integer of the operation
|
|
* @param power power that base is raised to
|
|
* @return base raised to exponent power (rounded by integer operations)
|
|
*/
|
|
public static int power(int base, int power) {
|
|
int result = 1;
|
|
int absPower = Math.abs(power);
|
|
for (int p = 0; p < absPower; p++) {
|
|
result *= base;
|
|
}
|
|
if (power < 0) {
|
|
// This will be zero for any base except 1 or -1
|
|
result = 1 / result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns the integer result of base^power
|
|
*
|
|
* Tested - works.
|
|
*
|
|
* @param base
|
|
* @param power
|
|
* @return
|
|
*/
|
|
public static long power(long base, long power) {
|
|
long result = 1;
|
|
long absPower = Math.abs(power);
|
|
for (long p = 0; p < absPower; p++) {
|
|
result *= base;
|
|
}
|
|
if (power < 0) {
|
|
// This will be zero for any base except 1 or -1
|
|
result = 1 / result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Compute n! (n factorial), without checking for overflow
|
|
*
|
|
* @param n
|
|
* @return
|
|
*/
|
|
public static long factorial(int n) {
|
|
long result = 1;
|
|
for (int i = 1; i <= n; i++) {
|
|
result *= (long) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Compute n! (n factorial), but check if this causes integer overflow
|
|
*
|
|
* @param n
|
|
* @return the integer (not long value of) n factorial
|
|
* @throws Exception when the result exceeds {@link Integer#MAX_VALUE}
|
|
*/
|
|
public static int factorialCheckBounds(int n) throws Exception {
|
|
// TODO I'm not convinced this is safe. Should just hard-code the limit.
|
|
long result = 1;
|
|
for (int i = 1; i <= n; i++) {
|
|
result *= (long) i;
|
|
if (result > Integer.MAX_VALUE) {
|
|
throw new Exception("n! causes integer overflow");
|
|
}
|
|
}
|
|
return (int) result;
|
|
}
|
|
|
|
public static double factorialAsDouble(int n) {
|
|
double result = 1;
|
|
for (int i = 1; i <= n; i++) {
|
|
result *= (double) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Computes n! as a double (to provide extended range over a long).
|
|
*
|
|
* We include the divisor here since n! hits with n at about 340.
|
|
* So if there is anything the result would have been divided by, we include it here,
|
|
* thus extending the range of n the function is suitable for.
|
|
*
|
|
* @param n
|
|
* @param divisor
|
|
* @return
|
|
*/
|
|
public static double factorialAsDoubleIncludeDivisor(int n, double divisor) {
|
|
double result = 1.0 / divisor;
|
|
for (int i = 1; i <= n; i++) {
|
|
result *= (double) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* n!!
|
|
* see http://en.wikipedia.org/wiki/Double_factorial#Double_factorial
|
|
*
|
|
* @param n
|
|
* @return
|
|
*/
|
|
public static long doubleFactorial(int n) {
|
|
long result = 1;
|
|
int startValue;
|
|
if (n % 2 == 0) {
|
|
// n even
|
|
startValue = 2;
|
|
} else {
|
|
// n odd
|
|
startValue = 3;
|
|
}
|
|
for (int i = startValue; i <= n; i += 2) {
|
|
result *= (long) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* n!!
|
|
* see http://en.wikipedia.org/wiki/Double_factorial#Double_factorial
|
|
*
|
|
* @param n
|
|
* @return
|
|
*/
|
|
public static double doubleFactorialAsDouble(int n) {
|
|
double result = 1.0;
|
|
int startValue;
|
|
if (n % 2 == 0) {
|
|
// n even
|
|
startValue = 2;
|
|
} else {
|
|
// n odd
|
|
startValue = 3;
|
|
}
|
|
for (int i = startValue; i <= n; i += 2) {
|
|
result *= (double) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* n!!
|
|
* see http://en.wikipedia.org/wiki/Double_factorial#Double_factorial
|
|
*
|
|
* We include the divisor here since the gamma(d/2+1) hits Inf with d just over 300.
|
|
* So if there is anything the result would have been divided by, we include it here,
|
|
* thus extending the range of d the function is suitable for.
|
|
*
|
|
* @param n
|
|
* @param divisor
|
|
* @return
|
|
*/
|
|
public static double doubleFactorialAsDoublewithDivisor(int n, double divisor) {
|
|
double result = 1.0 / divisor;
|
|
int startValue;
|
|
if (n % 2 == 0) {
|
|
// n even
|
|
startValue = 2;
|
|
} else {
|
|
// n odd
|
|
startValue = 3;
|
|
}
|
|
for (int i = startValue; i <= n; i += 2) {
|
|
result *= (double) i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Computes gamma(d/2 + 1)
|
|
* See http://en.wikipedia.org/wiki/Gamma_function
|
|
* for description of the analytical result for d odd.
|
|
* For d even, we have gamma of an integer, which is equal to
|
|
* (d/2)!
|
|
*
|
|
* @param d
|
|
* @return
|
|
*/
|
|
public static double gammaOfArgOn2Plus1(int d) {
|
|
if (d % 2 == 0) {
|
|
// d even
|
|
return factorialAsDouble(d/2);
|
|
} else {
|
|
// d odd
|
|
return Math.sqrt(Math.PI) * (double) doubleFactorialAsDouble(d) /
|
|
(double) Math.pow(2, ((double) (d + 1)) / 2.0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes gamma(d/2 + 1)/divisor
|
|
* See http://en.wikipedia.org/wiki/Gamma_function
|
|
* for description of the analytical result for d odd.
|
|
* For d even, we have gamma of an integer, which is equal to
|
|
* (d/2)!
|
|
*
|
|
* We include the divisor here since the gamma(d/2+1) hits Inf with d just over 300.
|
|
* So if there is anything the result would have been divided by, we include it here,
|
|
* thus extending the range of d the function is suitable for.
|
|
*
|
|
* @param d
|
|
* @param divisor
|
|
* @return
|
|
*/
|
|
public static double gammaOfArgOn2Plus1IncludeDivisor(int d, double divisor) {
|
|
if (d % 2 == 0) {
|
|
// d even
|
|
return factorialAsDoubleIncludeDivisor(d/2, divisor);
|
|
} else {
|
|
// d odd
|
|
return doubleFactorialAsDoublewithDivisor(d,
|
|
divisor * Math.pow(2, ((double) (d + 1)) / 2.0) / Math.sqrt(Math.PI));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compute digamma(d).
|
|
*
|
|
* Stores previous calculations to speed up computation here, though some precision may
|
|
* be lost because we're adding in larger numbers first.
|
|
*
|
|
* @param d
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public static double digamma(int d) throws Exception {
|
|
if (d < 1) {
|
|
return Double.NaN;
|
|
}
|
|
if (storedDigammas.length == 0) {
|
|
synchronized(storedDigammas) { // Ensure no race condition here
|
|
// We do two checks on whether the storage has been
|
|
// created so that the first is very fast (without
|
|
// requiring synchronization), and the second
|
|
// ensures no race condition.
|
|
if (storedDigammas.length == 0) {
|
|
// Using length == 0 as proxy to null, since
|
|
// we can't synchronize on a null object
|
|
|
|
// allocate space to store our results
|
|
storedDigammas = new double[NUM_STORED_DIGAMMAS];
|
|
storedDigammas[0] = Double.NaN;
|
|
storedDigammas[1] = -EULER_MASCHERONI_CONSTANT;
|
|
highestDigammaArgCalced = 1;
|
|
}
|
|
}
|
|
}
|
|
if (d <= highestDigammaArgCalced) {
|
|
// We've already calculated this one
|
|
return storedDigammas[d];
|
|
}
|
|
if (d >= NUM_STORED_DIGAMMAS) {
|
|
// Don't bother updating our storage,
|
|
// directly use commons.math:
|
|
return Gamma.digamma(d);
|
|
}
|
|
// Else we'll calculate it and update the storage:
|
|
double result = storedDigammas[highestDigammaArgCalced];
|
|
for (int n = highestDigammaArgCalced + 1; n <= d; n++) {
|
|
result += 1.0 / (double) (n-1);
|
|
// n must be < NUM_STORED_DIGAMMAS by earlier if statement on d
|
|
storedDigammas[n] = result;
|
|
}
|
|
highestDigammaArgCalced = d;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Compute the digamma function from first principles
|
|
*
|
|
* @param d
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public static double digammaByDefinition(int d) throws Exception {
|
|
if (d < 1) {
|
|
return Double.NaN;
|
|
}
|
|
double result = 0;
|
|
for (int n = d; n > 1; n--) {
|
|
result += 1.0 / (double) (n-1);
|
|
}
|
|
// Now add in result for n == 1
|
|
result += -EULER_MASCHERONI_CONSTANT;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* <p>Return the value of the cummulative distribution function of the
|
|
* chi-square distribution, evaluated at x, for k degrees of freedom.</p>
|
|
*
|
|
* <p>Note that this relies on our approximation of the error function,
|
|
* which is the limiting part of the accuracy. Testing against
|
|
* values produced by octave indicates this is accurate to 5-6
|
|
* decimal places.</p>
|
|
*
|
|
* @param x value at which to evaluate the CDF
|
|
* @param k degrees of freedom (must have k>0)
|
|
* @return chi squared CDF evaluated at x given k degrees of freedom
|
|
* @see {@link http://en.wikipedia.org/wiki/Chi-squared_distribution}
|
|
*/
|
|
public static double chiSquareCdf(double x, int k) {
|
|
if (k <= 0) {
|
|
throw new IllegalArgumentException("k (" + k + ") must be > 0");
|
|
}
|
|
// Old approach: (not numerically stable):
|
|
// return lowerIncompleteGammaFunctionOfArgsOn2(k,x) /
|
|
// gammaOfArgOn2Plus1(k-2); // denominator is Gamma(k/2)
|
|
// New approach:
|
|
return Gamma.regularizedGammaP(((double)k)/2.0, x/2.0);
|
|
}
|
|
|
|
/**
|
|
* Return the value of the lower Incomplete Gamma function,
|
|
* given arguments s/2 and x/2.
|
|
* We assume postive integer parameter s (s could be complex in general,
|
|
* with positive real part, but we restrict it to real and integer for
|
|
* this method). We make the evaluation using a recurrence relation,
|
|
* which terminates at s/2 = 1 or 1/2 (i.e. s = 2 or 1)
|
|
*
|
|
* @param s for parameter s/2 to lower incomplete gamma
|
|
* @param x for value x/2 to lower incomplete gamma
|
|
* @return value of lower gamma incomplete function
|
|
* @see {@link http://en.wikipedia.org/wiki/Incomplete_Gamma_function}
|
|
*/
|
|
public static double lowerIncompleteGammaFunctionOfArgsOn2(int s, double x) {
|
|
if (s <= 0) {
|
|
throw new IllegalArgumentException("s must be > 0");
|
|
}
|
|
if (s == 2) {
|
|
// Terminating condition: evaluate lower gamma(1, x/2):
|
|
return 1 - Math.exp(-x/2.0);
|
|
} else if (s == 1) {
|
|
// Terminating condition: evaluate lower gamma(1/2, x/2):
|
|
return Math.sqrt(Math.PI) * erf(Math.sqrt(x/2.0));
|
|
} else {
|
|
// Else evaluate recurrence relation:
|
|
return (s/2.0-1.0)*lowerIncompleteGammaFunctionOfArgsOn2(s-2,x) -
|
|
Math.pow(x/2.0, s/2.0 - 1.0) * Math.exp(-x/2.0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the value of the error function at a given x.
|
|
* We approximate the error function using elementary functions
|
|
* as described at the link below (quoting Abramowitz and Stegun).
|
|
* This approximation is quoted to
|
|
* have maximum error 1.5e-7 (and indeed this appears to be the
|
|
* case in comparison to values produced by octave).
|
|
*
|
|
* @param x value at which to evaluate the error function
|
|
* @return erf(x)
|
|
* @see {@link http://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions}
|
|
* @see Abramowitz, Milton; Stegun, Irene A., eds. (1972),
|
|
* "Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables",
|
|
* New York: Dover Publications, ISBN 978-0-486-61272-0
|
|
*/
|
|
public static double erf(double x) {
|
|
// Constants:
|
|
double p = 0.3275911;
|
|
double[] a = {0.254829592, -0.284496736, 1.421413741,
|
|
-1.453152027, 1.061405429};
|
|
boolean negArg = (x < 0);
|
|
|
|
if (negArg) {
|
|
// The rest of the method requires x >= 0, but since erf(x)
|
|
// is an odd function, we just reflect x.
|
|
x = -x;
|
|
}
|
|
|
|
double t = 1.0 / (1 + p * x);
|
|
double multiplier = 0.0;
|
|
double tToPower = t;
|
|
for (int i = 0; i < 5; i++) {
|
|
multiplier += a[i] * tToPower;
|
|
tToPower *= t;
|
|
}
|
|
double retVal = 1.0 - multiplier * Math.exp(-x*x);
|
|
// Remember that erf(x) was an odd function:
|
|
return negArg ? - retVal: retVal;
|
|
}
|
|
|
|
/**
|
|
* Compute the probability density function (PDF) of an observation
|
|
* x, given the mean mu, and the standard deviation sigma,
|
|
* given that the observations follow a univariate normal distribution.
|
|
*
|
|
* @param x observation
|
|
* @param mu mean of distribution
|
|
* @param sigma standard deviation (not the variance)
|
|
* @return PDF value
|
|
* @throws Exception when sigma < 0
|
|
*/
|
|
public static double normalPdf(double x, double mu, double sigma)
|
|
throws Exception {
|
|
if (sigma < 0) {
|
|
throw new Exception("Standard deviation cannot be < 0");
|
|
}
|
|
double expArg = (x - mu)/sigma;
|
|
expArg *= expArg;
|
|
double pdf =
|
|
Math.pow(2.0*Math.PI, -0.5) /
|
|
sigma *
|
|
Math.exp(-0.5 * expArg);
|
|
return pdf;
|
|
}
|
|
|
|
/**
|
|
* Compute the cumulative density function (CDF) of an observation
|
|
* x, given the mean mu, and the standard deviation sigma,
|
|
* given that the observations follow a univariate normal distribution.
|
|
*
|
|
* @param x observation
|
|
* @param mu mean of distribution
|
|
* @param sigma standard deviation (not the variance)
|
|
* @return CDF value
|
|
* @throws Exception when sigma < 0
|
|
*/
|
|
public static double normalCdf(double x, double mu, double sigma)
|
|
throws Exception {
|
|
if (sigma < 0) {
|
|
throw new Exception("Standard deviation cannot be < 0");
|
|
}
|
|
double erfArg = (x - mu)/Math.sqrt(2.0*sigma*sigma);
|
|
double cdf = 0.5 * (1 +
|
|
erf(erfArg));
|
|
return cdf;
|
|
}
|
|
|
|
|
|
/**
|
|
* Compute the probability density function (PDF) of a vector of observations
|
|
* x, given the means, and the
|
|
* covariance of the variables, given that the observations
|
|
* follow a multivariate normal distribution
|
|
*
|
|
* @param x observations
|
|
* @param means means of each variable
|
|
* @param covariance covariance matrix
|
|
* @return PDF value
|
|
* @throws Exception when the lengths of x and covariance
|
|
* do not match, or if supplied a non-square matrix, or if the covariance
|
|
* is not symmetric or not positive-definite.
|
|
*/
|
|
public static double normalPdf(double[] x, double[] means,
|
|
double[][] covariance) throws Exception {
|
|
if (x.length != means.length) {
|
|
throw new Exception("Length of observations must match means");
|
|
}
|
|
return normalPdf(MatrixUtils.subtract(x, means), covariance);
|
|
}
|
|
|
|
/**
|
|
* Compute the probability density function (PDF) of a vector of observations
|
|
* x, given the deviationsFromMean of x, i.e. (x - \mu), and the
|
|
* covariance of the variables, given that the observations
|
|
* follow a multivariate normal distribution
|
|
*
|
|
* @param deviationsFromMean x - \mu
|
|
* @param covariance
|
|
* @return PDF value
|
|
* @throws Exception when the lengths of deviationsFromMean and covariance
|
|
* do not match, or if supplied a non-square matrix, or if the covariance
|
|
* is not symmetric or not positive-definite.
|
|
*/
|
|
public static double normalPdf(double[] deviationsFromMean,
|
|
double[][] covariance) throws Exception {
|
|
if (deviationsFromMean.length != covariance.length) {
|
|
throw new Exception("Vector length of deviations does not " +
|
|
"match the size of the covariance matrix");
|
|
}
|
|
double det = MatrixUtils.determinant(covariance);
|
|
double[][] invCovariance = MatrixUtils.invertSymmPosDefMatrix(covariance);
|
|
double expArg = MatrixUtils.dotProduct(
|
|
MatrixUtils.matrixProduct(deviationsFromMean,
|
|
invCovariance),
|
|
deviationsFromMean);
|
|
double pdf =
|
|
Math.pow(2.0*Math.PI, -deviationsFromMean.length / 2.0) /
|
|
Math.sqrt(det) *
|
|
Math.exp(-0.5 * expArg);
|
|
return pdf;
|
|
}
|
|
|
|
/**
|
|
* Return the number of possible combinations of p from n (i.e. n choose p)
|
|
*
|
|
* @param n
|
|
* @param p
|
|
* @return
|
|
* @throws Exception if the number would be greater than Integer.MAX_INT
|
|
*/
|
|
public static int numOfSets(int n, int p) throws Exception {
|
|
// Compute how many sets there will be
|
|
long counter = n;
|
|
long numSets = 1;
|
|
for (int x = 1; x <= p; x++) {
|
|
numSets *= counter;
|
|
numSets /= x;
|
|
if (numSets > Integer.MAX_VALUE) {
|
|
throw new Exception("nCp causes integer overflow");
|
|
}
|
|
counter--;
|
|
}
|
|
// numSets counts the number of permutations of n.
|
|
// Need to get rid of repeats to make is combinations:
|
|
return (int) numSets;
|
|
}
|
|
|
|
/**
|
|
* Return an array of all possible combinations of p from n
|
|
*
|
|
* @param n
|
|
* @param p
|
|
* @return
|
|
* @throws Exception when the number of sets is greaterr than Integer.MAX_INT
|
|
*/
|
|
public static int[][] generateAllSets(int n, int p) throws Exception {
|
|
int numOfSets = numOfSets(n,p);
|
|
int[][] sets = new int[numOfSets][p];
|
|
int[] currentSet = new int[p];
|
|
writeSetsIn(n, p, 0, 0, currentSet, sets, 0);
|
|
return sets;
|
|
}
|
|
|
|
/**
|
|
* Recursive call used by generateAllSets.
|
|
*
|
|
* @param n
|
|
* @param p
|
|
* @param currentIndexInSet current index in currentSet that we are writing into
|
|
* @param currentSet current set containing indices already written into the upper parts
|
|
* @param sets array to write generated sets into
|
|
* @param upToSetNum
|
|
* @return new value of upToSetNum
|
|
*/
|
|
private static int writeSetsIn(int n, int p, int currentIndexInSet,
|
|
int firstCandidate, int[] currentSet, int[][] sets, int upToSetNum) {
|
|
/*
|
|
String indent = "";
|
|
for (int i = 0; i < currentIndexInSet; i++) {
|
|
indent += " ";
|
|
}
|
|
System.out.println(indent + String.format("currentIndex=%d", currentIndexInSet));
|
|
*/
|
|
// Put every candidate into this position:
|
|
for (int candidate = firstCandidate; candidate < n - p + currentIndexInSet + 1; candidate++) {
|
|
// System.out.println(indent + candidate);
|
|
currentSet[currentIndexInSet] = candidate;
|
|
if (currentIndexInSet == p - 1) {
|
|
// We just wrote the last index, so copy this one in and return
|
|
// System.out.println(indent + "writing into line " + upToSetNum);
|
|
System.arraycopy(currentSet, 0, sets[upToSetNum++], 0, p);
|
|
} else {
|
|
// There are more indices to be written in, so make a recursive call to write the
|
|
// next ones in
|
|
upToSetNum = writeSetsIn(n, p, currentIndexInSet + 1, candidate + 1, currentSet, sets, upToSetNum);
|
|
}
|
|
}
|
|
return upToSetNum;
|
|
}
|
|
|
|
/**
|
|
* Perform some testing:
|
|
*
|
|
* @param args
|
|
* @throws Exception
|
|
*/
|
|
public static void main(String args[]) throws Exception {
|
|
/*
|
|
System.out.println(numOfSets(158,4));
|
|
System.out.println(numOfSets(158,3));
|
|
System.out.println(numOfSets(158,2));
|
|
*/
|
|
// int[][] sets = generateAllSets(6,4);
|
|
// MatrixUtils.printMatrix(System.out, sets);
|
|
|
|
/*
|
|
System.out.printf("digamma() digammaOld()\n");
|
|
for (int n = 0; n < 100; n++) {
|
|
System.out.printf("%d %.3f %.3f\n", n, MathsUtils.digamma(n), MathsUtils.digammaByDefinition(n));
|
|
}
|
|
for (int n = 0; n < 101; n++) {
|
|
System.out.printf("%d %.3f %.3f\n", n, MathsUtils.digamma(n), MathsUtils.digammaByDefinition(n));
|
|
}
|
|
*/
|
|
|
|
/*
|
|
System.out.println("erf(" + 1 + ")= " + MathsUtils.erf(1));
|
|
System.out.println("erf(" + 2 + ")= " + MathsUtils.erf(2));
|
|
System.out.println("erf(" + 0 + ")= " + MathsUtils.erf(0));
|
|
for (int n=0; n<100; n++) {
|
|
System.out.println("erf(" + n*0.1 + ")= " + MathsUtils.erf(n*0.1));
|
|
}*/
|
|
|
|
int degFree = 10;
|
|
System.out.println("chi2cdf(1," + degFree +")= " + MathsUtils.chiSquareCdf(1, degFree));
|
|
System.out.println("chi2cdf(2," + degFree +")= " + MathsUtils.chiSquareCdf(2, degFree));
|
|
System.out.println("chi2cdf(3," + degFree +")= " + MathsUtils.chiSquareCdf(3, degFree));
|
|
for (int n=0; n<100; n++) {
|
|
System.out.println("chi2cdf(" + n*0.1 + "," + degFree +")= " + MathsUtils.chiSquareCdf(n*0.1, degFree));
|
|
}
|
|
|
|
}
|
|
}
|