mirror of https://github.com/jlizier/jidt
339 lines
12 KiB
Java
339 lines
12 KiB
Java
/*
|
|
* Java Information Dynamics Toolkit (JIDT)
|
|
* Copyright (C) 2017, 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/>.
|
|
*/
|
|
|
|
/*
|
|
* This class was originally distributed as part of the Apache Commons
|
|
* Math3 library (3.6.1), under the Apache License Version 2.0, which is
|
|
* copied below. This Apache 2 software is now included as a derivative
|
|
* work in the GPLv3 licensed JIDT project, as per:
|
|
* http://www.apache.org/licenses/GPL-compatibility.html
|
|
*
|
|
* The original Apache source code has been modified as follows:
|
|
* -- We have modified package names to sit inside the JIDT structure.
|
|
*/
|
|
|
|
/*
|
|
* 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 infodynamics.utils.commonsmath3.util;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import infodynamics.utils.commonsmath3.RealFieldElement;
|
|
import infodynamics.utils.commonsmath3.exception.MathArithmeticException;
|
|
import infodynamics.utils.commonsmath3.exception.NotFiniteNumberException;
|
|
import infodynamics.utils.commonsmath3.exception.NullArgumentException;
|
|
import infodynamics.utils.commonsmath3.exception.util.Localizable;
|
|
import infodynamics.utils.commonsmath3.exception.util.LocalizedFormats;
|
|
|
|
/**
|
|
* Miscellaneous utility functions.
|
|
*
|
|
* @see ArithmeticUtils
|
|
* @see Precision
|
|
* @see MathArrays
|
|
*
|
|
*/
|
|
public final class MathUtils {
|
|
/**
|
|
* \(2\pi\)
|
|
* @since 2.1
|
|
*/
|
|
public static final double TWO_PI = 2 * FastMath.PI;
|
|
|
|
/**
|
|
* \(\pi^2\)
|
|
* @since 3.4
|
|
*/
|
|
public static final double PI_SQUARED = FastMath.PI * FastMath.PI;
|
|
|
|
|
|
/**
|
|
* Class contains only static methods.
|
|
*/
|
|
private MathUtils() {}
|
|
|
|
|
|
/**
|
|
* Returns an integer hash code representing the given double value.
|
|
*
|
|
* @param value the value to be hashed
|
|
* @return the hash code
|
|
*/
|
|
public static int hash(double value) {
|
|
return new Double(value).hashCode();
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the values are equal according to semantics of
|
|
* {@link Double#equals(Object)}.
|
|
*
|
|
* @param x Value
|
|
* @param y Value
|
|
* @return {@code new Double(x).equals(new Double(y))}
|
|
*/
|
|
public static boolean equals(double x, double y) {
|
|
return new Double(x).equals(new Double(y));
|
|
}
|
|
|
|
/**
|
|
* Returns an integer hash code representing the given double array.
|
|
*
|
|
* @param value the value to be hashed (may be null)
|
|
* @return the hash code
|
|
* @since 1.2
|
|
*/
|
|
public static int hash(double[] value) {
|
|
return Arrays.hashCode(value);
|
|
}
|
|
|
|
/**
|
|
* Normalize an angle in a 2π wide interval around a center value.
|
|
* <p>This method has three main uses:</p>
|
|
* <ul>
|
|
* <li>normalize an angle between 0 and 2π:<br/>
|
|
* {@code a = MathUtils.normalizeAngle(a, FastMath.PI);}</li>
|
|
* <li>normalize an angle between -π and +π<br/>
|
|
* {@code a = MathUtils.normalizeAngle(a, 0.0);}</li>
|
|
* <li>compute the angle between two defining angular positions:<br>
|
|
* {@code angle = MathUtils.normalizeAngle(end, start) - start;}</li>
|
|
* </ul>
|
|
* <p>Note that due to numerical accuracy and since π cannot be represented
|
|
* exactly, the result interval is <em>closed</em>, it cannot be half-closed
|
|
* as would be more satisfactory in a purely mathematical view.</p>
|
|
* @param a angle to normalize
|
|
* @param center center of the desired 2π interval for the result
|
|
* @return a-2kπ with integer k and center-π <= a-2kπ <= center+π
|
|
* @since 1.2
|
|
*/
|
|
public static double normalizeAngle(double a, double center) {
|
|
return a - TWO_PI * FastMath.floor((a + FastMath.PI - center) / TWO_PI);
|
|
}
|
|
|
|
/** Find the maximum of two field elements.
|
|
* @param <T> the type of the field elements
|
|
* @param e1 first element
|
|
* @param e2 second element
|
|
* @return max(a1, e2)
|
|
* @since 3.6
|
|
*/
|
|
public static <T extends RealFieldElement<T>> T max(final T e1, final T e2) {
|
|
return e1.subtract(e2).getReal() >= 0 ? e1 : e2;
|
|
}
|
|
|
|
/** Find the minimum of two field elements.
|
|
* @param <T> the type of the field elements
|
|
* @param e1 first element
|
|
* @param e2 second element
|
|
* @return min(a1, e2)
|
|
* @since 3.6
|
|
*/
|
|
public static <T extends RealFieldElement<T>> T min(final T e1, final T e2) {
|
|
return e1.subtract(e2).getReal() >= 0 ? e2 : e1;
|
|
}
|
|
|
|
/**
|
|
* <p>Reduce {@code |a - offset|} to the primary interval
|
|
* {@code [0, |period|)}.</p>
|
|
*
|
|
* <p>Specifically, the value returned is <br/>
|
|
* {@code a - |period| * floor((a - offset) / |period|) - offset}.</p>
|
|
*
|
|
* <p>If any of the parameters are {@code NaN} or infinite, the result is
|
|
* {@code NaN}.</p>
|
|
*
|
|
* @param a Value to reduce.
|
|
* @param period Period.
|
|
* @param offset Value that will be mapped to {@code 0}.
|
|
* @return the value, within the interval {@code [0 |period|)},
|
|
* that corresponds to {@code a}.
|
|
*/
|
|
public static double reduce(double a,
|
|
double period,
|
|
double offset) {
|
|
final double p = FastMath.abs(period);
|
|
return a - p * FastMath.floor((a - offset) / p) - offset;
|
|
}
|
|
|
|
/**
|
|
* Returns the first argument with the sign of the second argument.
|
|
*
|
|
* @param magnitude Magnitude of the returned value.
|
|
* @param sign Sign of the returned value.
|
|
* @return a value with magnitude equal to {@code magnitude} and with the
|
|
* same sign as the {@code sign} argument.
|
|
* @throws MathArithmeticException if {@code magnitude == Byte.MIN_VALUE}
|
|
* and {@code sign >= 0}.
|
|
*/
|
|
public static byte copySign(byte magnitude, byte sign)
|
|
throws MathArithmeticException {
|
|
if ((magnitude >= 0 && sign >= 0) ||
|
|
(magnitude < 0 && sign < 0)) { // Sign is OK.
|
|
return magnitude;
|
|
} else if (sign >= 0 &&
|
|
magnitude == Byte.MIN_VALUE) {
|
|
throw new MathArithmeticException(LocalizedFormats.OVERFLOW);
|
|
} else {
|
|
return (byte) -magnitude; // Flip sign.
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the first argument with the sign of the second argument.
|
|
*
|
|
* @param magnitude Magnitude of the returned value.
|
|
* @param sign Sign of the returned value.
|
|
* @return a value with magnitude equal to {@code magnitude} and with the
|
|
* same sign as the {@code sign} argument.
|
|
* @throws MathArithmeticException if {@code magnitude == Short.MIN_VALUE}
|
|
* and {@code sign >= 0}.
|
|
*/
|
|
public static short copySign(short magnitude, short sign)
|
|
throws MathArithmeticException {
|
|
if ((magnitude >= 0 && sign >= 0) ||
|
|
(magnitude < 0 && sign < 0)) { // Sign is OK.
|
|
return magnitude;
|
|
} else if (sign >= 0 &&
|
|
magnitude == Short.MIN_VALUE) {
|
|
throw new MathArithmeticException(LocalizedFormats.OVERFLOW);
|
|
} else {
|
|
return (short) -magnitude; // Flip sign.
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the first argument with the sign of the second argument.
|
|
*
|
|
* @param magnitude Magnitude of the returned value.
|
|
* @param sign Sign of the returned value.
|
|
* @return a value with magnitude equal to {@code magnitude} and with the
|
|
* same sign as the {@code sign} argument.
|
|
* @throws MathArithmeticException if {@code magnitude == Integer.MIN_VALUE}
|
|
* and {@code sign >= 0}.
|
|
*/
|
|
public static int copySign(int magnitude, int sign)
|
|
throws MathArithmeticException {
|
|
if ((magnitude >= 0 && sign >= 0) ||
|
|
(magnitude < 0 && sign < 0)) { // Sign is OK.
|
|
return magnitude;
|
|
} else if (sign >= 0 &&
|
|
magnitude == Integer.MIN_VALUE) {
|
|
throw new MathArithmeticException(LocalizedFormats.OVERFLOW);
|
|
} else {
|
|
return -magnitude; // Flip sign.
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the first argument with the sign of the second argument.
|
|
*
|
|
* @param magnitude Magnitude of the returned value.
|
|
* @param sign Sign of the returned value.
|
|
* @return a value with magnitude equal to {@code magnitude} and with the
|
|
* same sign as the {@code sign} argument.
|
|
* @throws MathArithmeticException if {@code magnitude == Long.MIN_VALUE}
|
|
* and {@code sign >= 0}.
|
|
*/
|
|
public static long copySign(long magnitude, long sign)
|
|
throws MathArithmeticException {
|
|
if ((magnitude >= 0 && sign >= 0) ||
|
|
(magnitude < 0 && sign < 0)) { // Sign is OK.
|
|
return magnitude;
|
|
} else if (sign >= 0 &&
|
|
magnitude == Long.MIN_VALUE) {
|
|
throw new MathArithmeticException(LocalizedFormats.OVERFLOW);
|
|
} else {
|
|
return -magnitude; // Flip sign.
|
|
}
|
|
}
|
|
/**
|
|
* Check that the argument is a real number.
|
|
*
|
|
* @param x Argument.
|
|
* @throws NotFiniteNumberException if {@code x} is not a
|
|
* finite real number.
|
|
*/
|
|
public static void checkFinite(final double x)
|
|
throws NotFiniteNumberException {
|
|
if (Double.isInfinite(x) || Double.isNaN(x)) {
|
|
throw new NotFiniteNumberException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check that all the elements are real numbers.
|
|
*
|
|
* @param val Arguments.
|
|
* @throws NotFiniteNumberException if any values of the array is not a
|
|
* finite real number.
|
|
*/
|
|
public static void checkFinite(final double[] val)
|
|
throws NotFiniteNumberException {
|
|
for (int i = 0; i < val.length; i++) {
|
|
final double x = val[i];
|
|
if (Double.isInfinite(x) || Double.isNaN(x)) {
|
|
throw new NotFiniteNumberException(LocalizedFormats.ARRAY_ELEMENT, x, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that an object is not null.
|
|
*
|
|
* @param o Object to be checked.
|
|
* @param pattern Message pattern.
|
|
* @param args Arguments to replace the placeholders in {@code pattern}.
|
|
* @throws NullArgumentException if {@code o} is {@code null}.
|
|
*/
|
|
public static void checkNotNull(Object o,
|
|
Localizable pattern,
|
|
Object ... args)
|
|
throws NullArgumentException {
|
|
if (o == null) {
|
|
throw new NullArgumentException(pattern, args);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that an object is not null.
|
|
*
|
|
* @param o Object to be checked.
|
|
* @throws NullArgumentException if {@code o} is {@code null}.
|
|
*/
|
|
public static void checkNotNull(Object o)
|
|
throws NullArgumentException {
|
|
if (o == null) {
|
|
throw new NullArgumentException();
|
|
}
|
|
}
|
|
}
|