📄 mathutils.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.commons.math.util;import java.math.BigDecimal;/** * Some useful additions to the built-in functions in {@link Math}. * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $ */public final class MathUtils { /** -1.0 cast as a byte. */ private static final byte NB = (byte)-1; /** -1.0 cast as a short. */ private static final short NS = (short)-1; /** 1.0 cast as a byte. */ private static final byte PB = (byte)1; /** 1.0 cast as a short. */ private static final short PS = (short)1; /** 0.0 cast as a byte. */ private static final byte ZB = (byte)0; /** 0.0 cast as a short. */ private static final short ZS = (short)0; /** 2 π. */ private static final double TWO_PI = 2 * Math.PI; /** * Private Constructor */ private MathUtils() { super(); } /** * Add two integers, checking for overflow. * * @param x an addend * @param y an addend * @return the sum <code>x+y</code> * @throws ArithmeticException if the result can not be represented as an * int * @since 1.1 */ public static int addAndCheck(int x, int y) { long s = (long)x + (long)y; if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { throw new ArithmeticException("overflow: add"); } return (int)s; } /** * Add two long integers, checking for overflow. * * @param a an addend * @param b an addend * @return the sum <code>a+b</code> * @throws ArithmeticException if the result can not be represented as an * long * @since 1.2 */ public static long addAndCheck(long a, long b) { return addAndCheck(a, b, "overflow: add"); } /** * Add two long integers, checking for overflow. * * @param a an addend * @param b an addend * @param msg the message to use for any thrown exception. * @return the sum <code>a+b</code> * @throws ArithmeticException if the result can not be represented as an * long * @since 1.2 */ private static long addAndCheck(long a, long b, String msg) { long ret; if (a > b) { // use symmetry to reduce boundry cases ret = addAndCheck(b, a, msg); } else { // assert a <= b if (a < 0) { if (b < 0) { // check for negative overflow if (Long.MIN_VALUE - b <= a) { ret = a + b; } else { throw new ArithmeticException(msg); } } else { // oppisite sign addition is always safe ret = a + b; } } else { // assert a >= 0 // assert b >= 0 // check for positive overflow if (a <= Long.MAX_VALUE - b) { ret = a + b; } else { throw new ArithmeticException(msg); } } } return ret; } /** * Returns an exact representation of the <a * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial * Coefficient</a>, "<code>n choose k</code>", the number of * <code>k</code>-element subsets that can be selected from an * <code>n</code>-element set. * <p> * <Strong>Preconditions</strong>: * <ul> * <li> <code>0 <= k <= n </code> (otherwise * <code>IllegalArgumentException</code> is thrown)</li> * <li> The result is small enough to fit into a <code>long</code>. The * largest value of <code>n</code> for which all coefficients are * <code> < Long.MAX_VALUE</code> is 66. If the computed value exceeds * <code>Long.MAX_VALUE</code> an <code>ArithMeticException * </code> is * thrown.</li> * </ul></p> * * @param n the size of the set * @param k the size of the subsets to be counted * @return <code>n choose k</code> * @throws IllegalArgumentException if preconditions are not met. * @throws ArithmeticException if the result is too large to be represented * by a long integer. */ public static long binomialCoefficient(final int n, final int k) { if (n < k) { throw new IllegalArgumentException( "must have n >= k for binomial coefficient (n,k)"); } if (n < 0) { throw new IllegalArgumentException( "must have n >= 0 for binomial coefficient (n,k)"); } if ((n == k) || (k == 0)) { return 1; } if ((k == 1) || (k == n - 1)) { return n; } long result = Math.round(binomialCoefficientDouble(n, k)); if (result == Long.MAX_VALUE) { throw new ArithmeticException( "result too large to represent in a long integer"); } return result; } /** * Returns a <code>double</code> representation of the <a * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial * Coefficient</a>, "<code>n choose k</code>", the number of * <code>k</code>-element subsets that can be selected from an * <code>n</code>-element set. * <p> * <Strong>Preconditions</strong>: * <ul> * <li> <code>0 <= k <= n </code> (otherwise * <code>IllegalArgumentException</code> is thrown)</li> * <li> The result is small enough to fit into a <code>double</code>. The * largest value of <code>n</code> for which all coefficients are < * Double.MAX_VALUE is 1029. If the computed value exceeds Double.MAX_VALUE, * Double.POSITIVE_INFINITY is returned</li> * </ul></p> * * @param n the size of the set * @param k the size of the subsets to be counted * @return <code>n choose k</code> * @throws IllegalArgumentException if preconditions are not met. */ public static double binomialCoefficientDouble(final int n, final int k) { return Math.floor(Math.exp(binomialCoefficientLog(n, k)) + 0.5); } /** * Returns the natural <code>log</code> of the <a * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial * Coefficient</a>, "<code>n choose k</code>", the number of * <code>k</code>-element subsets that can be selected from an * <code>n</code>-element set. * <p> * <Strong>Preconditions</strong>: * <ul> * <li> <code>0 <= k <= n </code> (otherwise * <code>IllegalArgumentException</code> is thrown)</li> * </ul></p> * * @param n the size of the set * @param k the size of the subsets to be counted * @return <code>n choose k</code> * @throws IllegalArgumentException if preconditions are not met. */ public static double binomialCoefficientLog(final int n, final int k) { if (n < k) { throw new IllegalArgumentException( "must have n >= k for binomial coefficient (n,k)"); } if (n < 0) { throw new IllegalArgumentException( "must have n >= 0 for binomial coefficient (n,k)"); } if ((n == k) || (k == 0)) { return 0; } if ((k == 1) || (k == n - 1)) { return Math.log((double)n); } double logSum = 0; // n!/k! for (int i = k + 1; i <= n; i++) { logSum += Math.log((double)i); } // divide by (n-k)! for (int i = 2; i <= n - k; i++) { logSum -= Math.log((double)i); } return logSum; } /** * Returns the <a href="http://mathworld.wolfram.com/HyperbolicCosine.html"> * hyperbolic cosine</a> of x. * * @param x double value for which to find the hyperbolic cosine * @return hyperbolic cosine of x */ public static double cosh(double x) { return (Math.exp(x) + Math.exp(-x)) / 2.0; } /** * Returns true iff both arguments are NaN or neither is NaN and they are * equal * * @param x first value * @param y second value * @return true if the values are equal or both are NaN */ public static boolean equals(double x, double y) { return ((Double.isNaN(x) && Double.isNaN(y)) || x == y); } /** * Returns true iff both arguments are null or have same dimensions * and all their elements are {@link #equals(double,double) equals} * * @param x first array * @param y second array * @return true if the values are both null or have same dimension * and equal elements * @since 1.2 */ public static boolean equals(double[] x, double[] y) { if ((x == null) || (y == null)) { return !((x == null) ^ (y == null)); } if (x.length != y.length) { return false; } for (int i = 0; i < x.length; ++i) { if (!equals(x[i], y[i])) { return false; } } return true; } /** * Returns n!. Shorthand for <code>n</code> <a * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the * product of the numbers <code>1,...,n</code>. * <p> * <Strong>Preconditions</strong>: * <ul> * <li> <code>n >= 0</code> (otherwise * <code>IllegalArgumentException</code> is thrown)</li> * <li> The result is small enough to fit into a <code>long</code>. The * largest value of <code>n</code> for which <code>n!</code> < * Long.MAX_VALUE</code> is 20. If the computed value exceeds <code>Long.MAX_VALUE</code> * an <code>ArithMeticException </code> is thrown.</li> * </ul> * </p> * * @param n argument * @return <code>n!</code> * @throws ArithmeticException if the result is too large to be represented * by a long integer. * @throws IllegalArgumentException if n < 0 */ public static long factorial(final int n) { long result = Math.round(factorialDouble(n)); if (result == Long.MAX_VALUE) { throw new ArithmeticException( "result too large to represent in a long integer"); } return result; } /** * Returns n!. Shorthand for <code>n</code> <a * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the * product of the numbers <code>1,...,n</code> as a <code>double</code>. * <p> * <Strong>Preconditions</strong>: * <ul> * <li> <code>n >= 0</code> (otherwise * <code>IllegalArgumentException</code> is thrown)</li> * <li> The result is small enough to fit into a <code>double</code>. The * largest value of <code>n</code> for which <code>n!</code> < * Double.MAX_VALUE</code> is 170. If the computed value exceeds
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -