package JSci.maths;
/**
* The extra math library.
* Provides extra functions not in java.lang.Math class.
* This class cannot be subclassed or instantiated because all methods are static.
* @version 1.2
* @author Mark Hale
*/
public final class ExtraMath extends AbstractMath {
private ExtraMath() {}
/**
* Rounds a number to so many significant figures.
* @param x a number to be rounded.
* @param significant number of significant figures to round to.
*/
public static double round(final double x, final int significant) {
if(x == 0.0)
return x;
else if(significant == 0)
return 0.0;
final double signedExp = log10(Math.abs(x)) - significant;
if(signedExp < 0.0) {
// keep the exponent positive so factor is representable
final double factor = Math.pow(10.0, Math.floor(-signedExp));
return Math.round(x*factor)/factor;
} else {
final double factor = Math.pow(10.0, Math.ceil(signedExp));
return Math.round(x/factor)*factor;
}
}
/**
* Returns a random number within a specified range.
*/
public static double random(double min, double max) {
return (max-min)*Math.random()+min;
}
/**
* Returns the sign of a number.
* @return 1 if x>0.0, -1 if x<0.0, else 0.
*/
public static int sign(double x) {
if(x > 0.0)
return 1;
else if(x < 0.0)
return -1;
else
return 0;
}
/**
* Returns sqrt(x<sup>2</sup>+y<sup>2</sup>).
*/
public static double hypot(final double x,final double y) {
final double xAbs=Math.abs(x);
final double yAbs=Math.abs(y);
if(xAbs==0.0 && yAbs==0.0)
return 0.0;
else if(xAbs<yAbs)
return yAbs*Math.sqrt(1.0+(x/y)*(x/y));
else
return xAbs*Math.sqrt(1.0+(y/x)*(y/x));
}
/**
* Returns a<sup>b</sup>.
* @param a an integer.
* @param b a positive integer.
*/
public static int pow(int a, int b) {
if(b < 0) {
throw new IllegalArgumentException(b+" must be a positive integer.");
} else if(b == 0) {
return 1;
} else {
if(a == 0) {
return 0;
} else if(a == 1) {
return 1;
} else if(a == 2) {
return 1<<b;
} else {
for(int i=1; i<b; i++)
a *= a;
return a;
}
}
}
/**
* Returns 2<sup>a</sup>.
* @param a a positive integer.
*/
public static int pow2(int a) {
return 1<<a;
}
/**
* Returns the factorial.
* (Wrapper for the gamma function).
* @see SpecialMath#gamma
* @param x a double.
*/
public static double factorial(double x) {
return SpecialMath.gamma(x+1.0);
}
/**
* Returns the natural logarithm of the factorial.
* (Wrapper for the log gamma function).
* @see SpecialMath#logGamma
* @param x a double.
*/
public static double logFactorial(double x) {
return SpecialMath.logGamma(x+1.0);
}
/**
* Returns the binomial coefficient (n k).
* Uses Pascal's recursion formula.
* @jsci.planetmath PascalsRule
* @param n an integer.
* @param k an integer.
*/
public static int binomial(int n,int k) {
if(k == n || k ==0)
return 1;
else if(n == 0)
return 1;
else
return binomial(n-1, k-1)+binomial(n-1, k);
}
/**
* Returns the binomial coefficient (n k).
* Uses gamma functions.
* @jsci.planetmath BinomialCoefficient
* @param n a double.
* @param k a double.
*/
public static double binomial(double n,double k) {
return Math.exp(SpecialMath.logGamma(n+1.0)-SpecialMath.logGamma(k+1.0)-SpecialMath.logGamma(n-k+1.0));
}
/**
* Returns the base 10 logarithm of a double.
* @param x a double.
*/
public static double log10(double x) {
return Math.log(x)/NumericalConstants.LOG10;
}
/**
* Returns the hyperbolic sine of a double.
* @param x a double.
*/
public static double sinh(double x) {
return (Math.exp(x)-Math.exp(-x))/2.0;
}
/**
* Returns the hyperbolic cosine of a double.
* @param x a double.
*/
public static double cosh(double x) {
return (Math.exp(x)+Math.exp(-x))/2.0;
}
/**
* Returns the hyperbolic tangent of a double.
* @param x a double.
*/
public static double tanh(double x) {
return sinh(x)/cosh(x);
}
/**
* Returns the hyperbolic cotangent of a <code>double</code> value.
* <p>The identity is:
* <p><i>coth(x) = (e<sup>x</sup> + e<sup>-x</sup>)/(e<sup>x</sup> - e<sup>-x</sup>)</i>,
* in other words, {@linkplain Math#cosh cosh(<i>x</i>)}/{@linkplain Math#sinh sinh(<i>x</i>)}.
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, then the result is NaN.
* <li>If the argument is zero, then the result is an infinity with the same sign as the argument.
* <li>If the argument is positive infinity, then the result is <code>+1.0</code>.
* <li>If the argument is negative infinity, then the result is <code>-1.0</code>.
* </ul>
* @param x The number whose hyperbolic cotangent is sought
* @return The hyperbolic cotangent of <code>x</code>
*/
public static double
coth(double x) {
return 1.0D/tanh(x);
} //coth
/**
* Returns the hyperbolic cosecant of a <code>double</code> value.
* <p>The identity is:
* <p><i>csch(x) = (2/(e<sup>x</sup> - e<sup>-x</sup>)</i>,
* in other words, 1/{@linkplain Math#sinh sinh(<i>x</i>)}.
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, then the result is NaN.
* <li>If the argument is zero, then the result is an infinity with the same sign as the argument.
* <li>If the argument is positive infinity, then the result is <code>+0.0</code>.
* <li>If the argument is negative infinity, then the result is <code>-0.0</code>.
* </ul>
* @param x The number whose hyperbolic cosecant is sought
* @return The hyperbolic cosecant of <code>x</code>
*/
public static double
csch(double x) {
return 1.0D/sinh(x);
} //csch
/**
* Returns the hyperbolic secant of a <code>double</code> value.
* <p>The identity is:
* <p><i>sech(x) = (2/(e<sup>x</sup> + e<sup>-x</sup>)</i>,
* in other words, 1/{@linkplain Math#cosh cosh(<i>x</i>)}.
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, then the result is NaN.
* <li>If the argument is an infinity (positive or negative), then the result is <code>+0.0</code>.
* </ul>
* @param x The number whose hyperbolic secant is sought
* @return The hyperbolic secant of <code>x</code>
*/
public static double
sech(double x) {
return 1.0D/cosh(x);
} //sech
/**
* Returns the inverse hyperbolic sine of a <code>double</code> value.
* <p>The identity is:
* <p><i>asinh(x) = ln(x + sqrt(x<sup>2</sup> + 1))</i>
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, then the result is NaN.
* <li>If the argument is infinite, then the result is an infinity with the same sign as the argument.
* <li>If the argument is zero, then the result is a zero with the same sign as the argument.
* </ul>
* @param x The number whose inverse hyperbolic sine is sought
* @return The inverse hyperbolic sine of <code>x</code>
*/
public static double
asinh(double x) {
//Math.hypot(Double.NEGATIVE_INFINITY, 1.0D) is Double.POSITIVE_INFINITY
//return Double.isInfinite(x) ? x : (x == 0.0) ? x : Math.log(x + Math.hypot(x, 1.0D));
return Double.isInfinite(x) ? x : (x == 0.0) ? x : Math.log(x+Math.sqrt(x*x+1.0));
} //asinh
/**
* Returns the inverse hyperbolic cosine of a <code>double</code> value.
* Note that <i>cosh(acosh(x)) = x</i>; this function arbitrarily returns the positive branch.
* <p>The identity is:
* <p><i>acosh(x) = ln(x sqrt(x<sup>2</sup> - 1))</i>
* <p>Special cases:
* <ul>
* <li>If the argument is NaN or less than one, then the result is NaN.
* <li>If the argument is a positive infinity, then the result is (positive) infinity.
* <li>If the argument is one, then the result is (positive) zero.
* </ul>
* @param x The number whose inverse hyperbolic cosine is sought
* @return The inverse hyperbolic cosine of <code>x</code>
*/
public static double
acosh(double x) {
return Math.log(x + Math.sqrt(x*x - 1.0D));
} //acosh
/**
* Returns the inverse hyperbolic tangent of a <code>double</code> value.
* <p>The identity is:
* <p><i>atanh(x) = (1/2)*ln((1 + x)/(1 - x))</i>
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, an infinity, or has a modulus of greater than one, then the result is NaN.
* <li>If the argument is plus or minus one, then the result is infinity with the same sign as the argument.
* <li>If the argument is zero, then the result is a zero with the same sign as the argument.
* </ul>
* @param x A double specifying the value whose inverse hyperbolic tangent is sought
* @return A double specifying the inverse hyperbolic tangent of x
*/
public static double
atanh(double x) {
//return (Math.log1p(x) - Math.log1p(-x))/2.0D;
return (x != 0.0) ? (Math.log(1.0D + x)-Math.log(1.0D - x))/2.0D : x;
} //atanh
/**
* Returns the inverse hyperbolic cotangent of a <code>double</code> value.
* <p>The identity is:
* <p><i>acoth(x) = (1/2)*ln((x + 1)/(x - 1))</i>
* <p>Special cases:
* <ul>
* <li>If the argument is NaN or a modulus of less than one, then the result is NaN.
* <li>If the argument is an infinity, then the result is zero with the same sign as the argument.
* <li>If the argument is plus or minus one, then the result is infinity with the same sign as the argument.
* </ul>
* @param x The number whose inverse hyperbolic cotangent is sought
* @return The inverse hyperbolic cotangent of <code>x</code>
*/
public static double
acoth(double x) {
// return (Math.log1p(x) - Math.log(x - 1.0D))/2.0D; // Difference of two same-sign infinities is NaN
if (Double.isInfinite(x)) return (x < 0.0) ? -0.0D : +0.0D;
//return (x == -1.0D) ? Double.NEGATIVE_INFINITY : (Math.log1p(x) - Math.log(x - 1.0D))/2.0D;
return (x == -1.0D) ? Double.NEGATIVE_INFINITY : (Math.log(x+1.0) - Math.log(x - 1.0D))/2.0D;
} //acoth
/**
* Returns the inverse hyperbolic cosecant of a <code>double</code> value.
* <p>The identity is:
* <p><i>acsch(x) = ln((1 - sqrt(1 + x<sup>2</sup>))/x)</i> for x < 0;
* <p><i>acsch(x) = ln((1 + sqrt(1 + x<sup>2</sup>))/x)</i> for x > 0.
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, then the result is NaN.
* <li>If the argument is an infinity, then the result is zero with the same sign as the argument.
* <li>If the argument is zero, then the result is infinity with the same sign as the argument.
* </ul>
* @param x The number whose inverse hyperbolic cosecant is sought
* @return The inverse hyperbolic cosecant of <code>x</code>
*/
public static double
acsch(double x) {
// return (x < 0) ? Math.log((1.0D - Math.sqrt(Math.hypot(1.0, x)))/x) : Math.log((1.0D + Math.sqrt(1.0, x))/x);
if (Double.isInfinite(x)) return (x < 0.0) ? -0.0D : +0.0D;
//log(+infinity) is +infinity, but log(-infinity) is NaN
return (x == 0.0D) ? 1.0/x : Math.log((1.0D + sign(x)*Math.sqrt(x*x+1.0))/x);
} //acsch
/**
* Returns the inverse hyperbolic secant of a <code>double</code> value.
* Note that <i>sech(asech(x)) = x</i>; this function arbitrarily returns the positive branch.
* <p>The identity is:
* <p><i>asech(x) = ln((1 + sqrt(1 - x<sup>2</sup>))/x)</i>.
* <p>Special cases:
* <ul>
* <li>If the argument is NaN, less than zero, or greater than one, then the result is NaN.
* <li>If the argument is zero, then the result is infinity with the same sign as the argument.
* </ul>
* @param x The number whose hyperbolic secant is sought
* @return The hyperbolic secant of <code>x</code>
*/
public static double
asech(double x) {
//log(+infinity) is +infinity, but log(-infinity) is NaN
return (x == 0.0D) ? 1.0/x : Math.log((1.0D + Math.sqrt(1.0D - x*x))/x);
} //asech
}
|