001: package JSci.maths;
002:
003: /**
004: * The extra math library.
005: * Provides extra functions not in java.lang.Math class.
006: * This class cannot be subclassed or instantiated because all methods are static.
007: * @version 1.2
008: * @author Mark Hale
009: */
010: public final class ExtraMath extends AbstractMath {
011: private ExtraMath() {
012: }
013:
014: /**
015: * Rounds a number to so many significant figures.
016: * @param x a number to be rounded.
017: * @param significant number of significant figures to round to.
018: */
019: public static double round(final double x, final int significant) {
020: if (x == 0.0)
021: return x;
022: else if (significant == 0)
023: return 0.0;
024: final double signedExp = log10(Math.abs(x)) - significant;
025: if (signedExp < 0.0) {
026: // keep the exponent positive so factor is representable
027: final double factor = Math
028: .pow(10.0, Math.floor(-signedExp));
029: return Math.round(x * factor) / factor;
030: } else {
031: final double factor = Math.pow(10.0, Math.ceil(signedExp));
032: return Math.round(x / factor) * factor;
033: }
034: }
035:
036: /**
037: * Returns a random number within a specified range.
038: */
039: public static double random(double min, double max) {
040: return (max - min) * Math.random() + min;
041: }
042:
043: /**
044: * Returns the sign of a number.
045: * @return 1 if x>0.0, -1 if x<0.0, else 0.
046: */
047: public static int sign(double x) {
048: if (x > 0.0)
049: return 1;
050: else if (x < 0.0)
051: return -1;
052: else
053: return 0;
054: }
055:
056: /**
057: * Returns sqrt(x<sup>2</sup>+y<sup>2</sup>).
058: */
059: public static double hypot(final double x, final double y) {
060: final double xAbs = Math.abs(x);
061: final double yAbs = Math.abs(y);
062: if (xAbs == 0.0 && yAbs == 0.0)
063: return 0.0;
064: else if (xAbs < yAbs)
065: return yAbs * Math.sqrt(1.0 + (x / y) * (x / y));
066: else
067: return xAbs * Math.sqrt(1.0 + (y / x) * (y / x));
068: }
069:
070: /**
071: * Returns a<sup>b</sup>.
072: * @param a an integer.
073: * @param b a positive integer.
074: */
075: public static int pow(int a, int b) {
076: if (b < 0) {
077: throw new IllegalArgumentException(b
078: + " must be a positive integer.");
079: } else if (b == 0) {
080: return 1;
081: } else {
082: if (a == 0) {
083: return 0;
084: } else if (a == 1) {
085: return 1;
086: } else if (a == 2) {
087: return 1 << b;
088: } else {
089: for (int i = 1; i < b; i++)
090: a *= a;
091: return a;
092: }
093: }
094: }
095:
096: /**
097: * Returns 2<sup>a</sup>.
098: * @param a a positive integer.
099: */
100: public static int pow2(int a) {
101: return 1 << a;
102: }
103:
104: /**
105: * Returns the factorial.
106: * (Wrapper for the gamma function).
107: * @see SpecialMath#gamma
108: * @param x a double.
109: */
110: public static double factorial(double x) {
111: return SpecialMath.gamma(x + 1.0);
112: }
113:
114: /**
115: * Returns the natural logarithm of the factorial.
116: * (Wrapper for the log gamma function).
117: * @see SpecialMath#logGamma
118: * @param x a double.
119: */
120: public static double logFactorial(double x) {
121: return SpecialMath.logGamma(x + 1.0);
122: }
123:
124: /**
125: * Returns the binomial coefficient (n k).
126: * Uses Pascal's recursion formula.
127: * @jsci.planetmath PascalsRule
128: * @param n an integer.
129: * @param k an integer.
130: */
131: public static int binomial(int n, int k) {
132: if (k == n || k == 0)
133: return 1;
134: else if (n == 0)
135: return 1;
136: else
137: return binomial(n - 1, k - 1) + binomial(n - 1, k);
138: }
139:
140: /**
141: * Returns the binomial coefficient (n k).
142: * Uses gamma functions.
143: * @jsci.planetmath BinomialCoefficient
144: * @param n a double.
145: * @param k a double.
146: */
147: public static double binomial(double n, double k) {
148: return Math.exp(SpecialMath.logGamma(n + 1.0)
149: - SpecialMath.logGamma(k + 1.0)
150: - SpecialMath.logGamma(n - k + 1.0));
151: }
152:
153: /**
154: * Returns the base 10 logarithm of a double.
155: * @param x a double.
156: */
157: public static double log10(double x) {
158: return Math.log(x) / NumericalConstants.LOG10;
159: }
160:
161: /**
162: * Returns the hyperbolic sine of a double.
163: * @param x a double.
164: */
165: public static double sinh(double x) {
166: return (Math.exp(x) - Math.exp(-x)) / 2.0;
167: }
168:
169: /**
170: * Returns the hyperbolic cosine of a double.
171: * @param x a double.
172: */
173: public static double cosh(double x) {
174: return (Math.exp(x) + Math.exp(-x)) / 2.0;
175: }
176:
177: /**
178: * Returns the hyperbolic tangent of a double.
179: * @param x a double.
180: */
181: public static double tanh(double x) {
182: return sinh(x) / cosh(x);
183: }
184:
185: /**
186: * Returns the hyperbolic cotangent of a <code>double</code> value.
187: * <p>The identity is:
188: * <p><i>coth(x) = (e<sup>x</sup> + e<sup>-x</sup>)/(e<sup>x</sup> - e<sup>-x</sup>)</i>,
189:
190: * in other words, {@linkplain Math#cosh cosh(<i>x</i>)}/{@linkplain Math#sinh sinh(<i>x</i>)}.
191: * <p>Special cases:
192: * <ul>
193: * <li>If the argument is NaN, then the result is NaN.
194: * <li>If the argument is zero, then the result is an infinity with the same sign as the argument.
195: * <li>If the argument is positive infinity, then the result is <code>+1.0</code>.
196: * <li>If the argument is negative infinity, then the result is <code>-1.0</code>.
197: * </ul>
198: * @param x The number whose hyperbolic cotangent is sought
199: * @return The hyperbolic cotangent of <code>x</code>
200: */
201: public static double coth(double x) {
202: return 1.0D / tanh(x);
203: } //coth
204:
205: /**
206: * Returns the hyperbolic cosecant of a <code>double</code> value.
207: * <p>The identity is:
208: * <p><i>csch(x) = (2/(e<sup>x</sup> - e<sup>-x</sup>)</i>,
209: * in other words, 1/{@linkplain Math#sinh sinh(<i>x</i>)}.
210: * <p>Special cases:
211: * <ul>
212: * <li>If the argument is NaN, then the result is NaN.
213: * <li>If the argument is zero, then the result is an infinity with the same sign as the argument.
214: * <li>If the argument is positive infinity, then the result is <code>+0.0</code>.
215: * <li>If the argument is negative infinity, then the result is <code>-0.0</code>.
216: * </ul>
217: * @param x The number whose hyperbolic cosecant is sought
218: * @return The hyperbolic cosecant of <code>x</code>
219: */
220: public static double csch(double x) {
221: return 1.0D / sinh(x);
222: } //csch
223:
224: /**
225: * Returns the hyperbolic secant of a <code>double</code> value.
226: * <p>The identity is:
227: * <p><i>sech(x) = (2/(e<sup>x</sup> + e<sup>-x</sup>)</i>,
228: * in other words, 1/{@linkplain Math#cosh cosh(<i>x</i>)}.
229: * <p>Special cases:
230: * <ul>
231: * <li>If the argument is NaN, then the result is NaN.
232: * <li>If the argument is an infinity (positive or negative), then the result is <code>+0.0</code>.
233: * </ul>
234: * @param x The number whose hyperbolic secant is sought
235: * @return The hyperbolic secant of <code>x</code>
236: */
237: public static double sech(double x) {
238: return 1.0D / cosh(x);
239: } //sech
240:
241: /**
242: * Returns the inverse hyperbolic sine of a <code>double</code> value.
243: * <p>The identity is:
244: * <p><i>asinh(x) = ln(x + sqrt(x<sup>2</sup> + 1))</i>
245: * <p>Special cases:
246: * <ul>
247: * <li>If the argument is NaN, then the result is NaN.
248: * <li>If the argument is infinite, then the result is an infinity with the same sign as the argument.
249: * <li>If the argument is zero, then the result is a zero with the same sign as the argument.
250: * </ul>
251: * @param x The number whose inverse hyperbolic sine is sought
252: * @return The inverse hyperbolic sine of <code>x</code>
253: */
254: public static double asinh(double x) {
255: //Math.hypot(Double.NEGATIVE_INFINITY, 1.0D) is Double.POSITIVE_INFINITY
256: //return Double.isInfinite(x) ? x : (x == 0.0) ? x : Math.log(x + Math.hypot(x, 1.0D));
257: return Double.isInfinite(x) ? x : (x == 0.0) ? x : Math.log(x
258: + Math.sqrt(x * x + 1.0));
259: } //asinh
260:
261: /**
262: * Returns the inverse hyperbolic cosine of a <code>double</code> value.
263: * Note that <i>cosh(±acosh(x)) = x</i>; this function arbitrarily returns the positive branch.
264: * <p>The identity is:
265: * <p><i>acosh(x) = ln(x ± sqrt(x<sup>2</sup> - 1))</i>
266: * <p>Special cases:
267: * <ul>
268: * <li>If the argument is NaN or less than one, then the result is NaN.
269: * <li>If the argument is a positive infinity, then the result is (positive) infinity.
270: * <li>If the argument is one, then the result is (positive) zero.
271: * </ul>
272: * @param x The number whose inverse hyperbolic cosine is sought
273: * @return The inverse hyperbolic cosine of <code>x</code>
274: */
275: public static double acosh(double x) {
276: return Math.log(x + Math.sqrt(x * x - 1.0D));
277: } //acosh
278:
279: /**
280: * Returns the inverse hyperbolic tangent of a <code>double</code> value.
281: * <p>The identity is:
282: * <p><i>atanh(x) = (1/2)*ln((1 + x)/(1 - x))</i>
283: * <p>Special cases:
284: * <ul>
285: * <li>If the argument is NaN, an infinity, or has a modulus of greater than one, then the result is NaN.
286: * <li>If the argument is plus or minus one, then the result is infinity with the same sign as the argument.
287: * <li>If the argument is zero, then the result is a zero with the same sign as the argument.
288: * </ul>
289: * @param x A double specifying the value whose inverse hyperbolic tangent is sought
290: * @return A double specifying the inverse hyperbolic tangent of x
291: */
292: public static double atanh(double x) {
293: //return (Math.log1p(x) - Math.log1p(-x))/2.0D;
294: return (x != 0.0) ? (Math.log(1.0D + x) - Math.log(1.0D - x)) / 2.0D
295: : x;
296: } //atanh
297:
298: /**
299: * Returns the inverse hyperbolic cotangent of a <code>double</code> value.
300: * <p>The identity is:
301: * <p><i>acoth(x) = (1/2)*ln((x + 1)/(x - 1))</i>
302: * <p>Special cases:
303: * <ul>
304: * <li>If the argument is NaN or a modulus of less than one, then the result is NaN.
305: * <li>If the argument is an infinity, then the result is zero with the same sign as the argument.
306: * <li>If the argument is plus or minus one, then the result is infinity with the same sign as the argument.
307: * </ul>
308: * @param x The number whose inverse hyperbolic cotangent is sought
309: * @return The inverse hyperbolic cotangent of <code>x</code>
310: */
311: public static double acoth(double x) {
312: // return (Math.log1p(x) - Math.log(x - 1.0D))/2.0D; // Difference of two same-sign infinities is NaN
313: if (Double.isInfinite(x))
314: return (x < 0.0) ? -0.0D : +0.0D;
315: //return (x == -1.0D) ? Double.NEGATIVE_INFINITY : (Math.log1p(x) - Math.log(x - 1.0D))/2.0D;
316: return (x == -1.0D) ? Double.NEGATIVE_INFINITY : (Math
317: .log(x + 1.0) - Math.log(x - 1.0D)) / 2.0D;
318: } //acoth
319:
320: /**
321: * Returns the inverse hyperbolic cosecant of a <code>double</code> value.
322: * <p>The identity is:
323: * <p><i>acsch(x) = ln((1 - sqrt(1 + x<sup>2</sup>))/x)</i> for x < 0;
324: * <p><i>acsch(x) = ln((1 + sqrt(1 + x<sup>2</sup>))/x)</i> for x > 0.
325: * <p>Special cases:
326: * <ul>
327: * <li>If the argument is NaN, then the result is NaN.
328: * <li>If the argument is an infinity, then the result is zero with the same sign as the argument.
329: * <li>If the argument is zero, then the result is infinity with the same sign as the argument.
330: * </ul>
331: * @param x The number whose inverse hyperbolic cosecant is sought
332: * @return The inverse hyperbolic cosecant of <code>x</code>
333: */
334: public static double acsch(double x) {
335: // 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);
336:
337: if (Double.isInfinite(x))
338: return (x < 0.0) ? -0.0D : +0.0D;
339: //log(+infinity) is +infinity, but log(-infinity) is NaN
340: return (x == 0.0D) ? 1.0 / x : Math.log((1.0D + sign(x)
341: * Math.sqrt(x * x + 1.0))
342: / x);
343: } //acsch
344:
345: /**
346: * Returns the inverse hyperbolic secant of a <code>double</code> value.
347: * Note that <i>sech(±asech(x)) = x</i>; this function arbitrarily returns the positive branch.
348: * <p>The identity is:
349: * <p><i>asech(x) = ln((1 + sqrt(1 - x<sup>2</sup>))/x)</i>.
350: * <p>Special cases:
351: * <ul>
352: * <li>If the argument is NaN, less than zero, or greater than one, then the result is NaN.
353: * <li>If the argument is zero, then the result is infinity with the same sign as the argument.
354: * </ul>
355: * @param x The number whose hyperbolic secant is sought
356: * @return The hyperbolic secant of <code>x</code>
357: */
358: public static double asech(double x) {
359: //log(+infinity) is +infinity, but log(-infinity) is NaN
360: return (x == 0.0D) ? 1.0 / x : Math.log((1.0D + Math.sqrt(1.0D
361: - x * x))
362: / x);
363: } //asech
364: }
|