/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion 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. */ package illarion.common.util; import illarion.common.types.Range; import org.jetbrains.annotations.Contract; import javax.annotation.Nonnull; import java.util.Random; /** * This is the Java implementation of the FastMath class. This should only be * used in case the native implementation is not available or results in * problems. * * @author Martin Karing <nitram@illarion.org> */ @SuppressWarnings("NonReproducibleMathCall") public final class FastMath { /** * A "close to zero" double epsilon value for use. */ public static final double DBL_EPSILON = 2.220446049250313E-16d; /** * A value to multiply a degree value by, to convert it to radians. */ public static final float DEG_TO_RAD = (float) Math.PI / 180.0f; /** * The Euler value that is the base of the natural logarithms. */ public static final float E = (float) Math.E; /** * A "close to zero" float epsilon value for use. Also this is the delta of * the result floating point result that is meet for sure. */ public static final float FLT_EPSILON = 1.1920928955078125E-5f; /** * The value PI/2 as a float. (90 degrees) */ public static final float HALF_PI = 0.5f * (float) Math.PI; /** * The value 1/PI as a float. */ public static final float INV_PI = 1.0f / (float) Math.PI; /** * The value 1/(2PI) as a float. */ public static final float INV_TWO_PI = 1.0f / (2.0f * (float) Math.PI); /** * The float value of one third for use. */ public static final float ONE_THIRD = 1f / 3f; /** * The value PI as a float. (180 degrees) */ public static final float PI = (float) Math.PI; /** * The value PI/4 as a float. (45 degrees) */ public static final float QUARTER_PI = 0.25f * (float) Math.PI; /** * A value to multiply a radian value by, to convert it to degrees. */ public static final float RAD_TO_DEG = 180.0f / (float) Math.PI; /** * The value 2PI as a float. (360 degrees) */ public static final float TWO_PI = 2.0f * (float) Math.PI; /** * The used random value generator. */ @Nonnull private static final Random RANDOM = new Random(); /** * Lookup table for the fast square root table function. */ @Nonnull private static final int[] SQRT_TABLE = {0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255}; /** * Private constructor to ensure that no instance is created. */ private FastMath() { // nothing to do } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on byte values. <br> * Special case: In case the argument is set to Byte.MIN_VALUE the result * will be Byte.MIN_VALUE as well. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(double) * @see #abs(float) * @see #abs(int) * @see #abs(long) * @see #abs(short) */ @Contract(pure = true) public static byte abs(byte value) { return (byte) ((value ^ (value >> 7)) - (value >> 7)); } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on double values. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(byte) * @see #abs(float) * @see #abs(int) * @see #abs(long) * @see #abs(short) */ @Contract(pure = true) public static double abs(double value) { if (value < 0.d) { return -value; } return value; } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on float values. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(byte) * @see #abs(double) * @see #abs(int) * @see #abs(long) * @see #abs(short) */ @Contract(pure = true) public static float abs(float value) { if (value < 0.f) { return -value; } return value; } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on integer values. <br> * Special case: In case the argument is set to Integer.MIN_VALUE the result * will be Integer.MIN_VALUE as well. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(byte) * @see #abs(double) * @see #abs(float) * @see #abs(long) * @see #abs(short) */ @Contract(pure = true) public static int abs(int value) { return (value ^ (value >> 31)) - (value >> 31); } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on long values. <br> * Special case: In case the argument is set to Long.MIN_VALUE the result * will be Long.MIN_VALUE as well. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(byte) * @see #abs(double) * @see #abs(float) * @see #abs(int) * @see #abs(short) */ @Contract(pure = true) public static long abs(long value) { return (value ^ (value >> 63L)) - (value >> 63L); } /** * Returns absolute value of a value. This means a negative value gets * negated (so it becomes positive) and a positive value remains the same. * This version works on short values. * * @param value the value to work with * @return the absolute value of the value supplied as parameter * @see #abs(byte) * @see #abs(double) * @see #abs(float) * @see #abs(int) * @see #abs(long) */ @Contract(pure = true) public static short abs(short value) { return (short) ((value ^ (value >> 15)) - (value >> 15)); } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static byte acos(byte value) { throw new OutOfCoffeeException("A arc cosine from a byte value? No point in that."); } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. * <ul> * <li>If the argument is NaN or its absolute value is greater than 1, then * the result is NaN.</li> * </ul> * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @Contract(pure = true) public static double acos(double value) { if (Double.isNaN(value)) { return Double.NaN; } if (-1.d < value) { if (value < 1.d) { return Math.acos(value); } return Double.NaN; } return Double.NaN; } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. * <ul> * <li>If the argument is NaN or its absolute value is greater than 1, then * the result is NaN.</li> * </ul> * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @Contract(pure = true) public static float acos(float value) { if (Float.isNaN(value)) { return Float.NaN; } if (-1.f < value) { if (value < 1.f) { return (float) Math.acos(value); } return Float.NaN; } return Float.NaN; } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static int acos(int value) { throw new OutOfCoffeeException("A arc cosine from a integer value? No point in that."); } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static long acos(long value) { throw new OutOfCoffeeException("A arc cosine from a long value? No point in that."); } /** * Returns the arc cosine of a value; the returned angle is in the range 0.0 * through pi. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc cosine is to be returned * @return the arc cosine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static short acos(short value) { throw new OutOfCoffeeException("A arc cosine from a short value? No point in that."); } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static byte asin(byte value) { throw new OutOfCoffeeException("A arc sine from a byte value? No point in that."); } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. Special cases: * <ul> * <li>If the argument is NaN or its absolute value is greater than 1, then * the result is NaN.</li> * <li>If the argument is zero, then the result is a zero with the same sign * as the argument.</li> * </ul> * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @Contract(pure = true) public static double asin(double value) { if (!isNumber(value)) { return Double.NaN; } if (-1.0f < value) { if (value < 1.0f) { return Math.asin(value); } return Double.NaN; } return Double.NaN; } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. Special cases: * <ul> * <li>If the argument is NaN or its absolute value is greater than 1, then * the result is NaN.</li> * <li>If the argument is zero, then the result is a zero with the same sign * as the argument.</li> * </ul> * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @Contract(pure = true) public static float asin(float value) { if (!isNumber(value)) { return Float.NaN; } if (-1.0f < value) { if (value < 1.0f) { return (float) Math.asin(value); } return Float.NaN; } return Float.NaN; } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static int asin(int value) { throw new OutOfCoffeeException("A arc sine from a integer value? No point in that."); } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static long asin(long value) { throw new OutOfCoffeeException("A arc sine from a long value? No point in that."); } /** * Returns the arc sine of a value; the returned angle is in the range -pi/2 * through pi/2. This function results in a error message all and is only * implemented to ensure that no one calls that function for a false data * type by mistake. * * @param value the value whose arc sine is to be returned * @return the arc sine of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static short asin(short value) { throw new OutOfCoffeeException("A arc sine from a short value? No point in that."); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using byte values. * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static float atan(byte value) { return (float) Math.atan(value); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using double * values. Special cases: * <ul> * <li>If the argument is NaN, then the result is NaN.</li> * <li>If the argument is zero, then the result is a zero with the same sign * as the argument.</li> * </ul> * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static double atan(double value) { return Math.atan(value); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using float * values. Special cases: * <ul> * <li>If the argument is NaN, then the result is NaN.</li> * <li>If the argument is zero, then the result is a zero with the same sign * as the argument.</li> * </ul> * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static float atan(float value) { return (float) Math.atan(value); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using integer * values. * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static float atan(int value) { return (float) Math.atan(value); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using long values. * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static double atan(long value) { return Math.atan(value); } /** * Returns the arc tangent of a value; the returned angle is in the range * -pi/2 through pi/2. This version of the function works using short * values. * * @param value the value whose arc tangent is to be returned * @return the arc tangent of the argument */ @Contract(pure = true) public static float atan(short value) { return (float) Math.atan(value); } /** * Round a byte value to the next larger byte value.<br> * <b>This function throws a exception at any time because its absolutely * useless to round a byte value. This function is only implemented to * prevent useless function calls.</b> * * @param value the value that needs to be rounded * @return the next larger short of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static byte ceil(byte value) { throw new OutOfCoffeeException("Rounding up a byte value? Seriously?"); } /** * Round a double value to the next larger long value. Special cases: * <ul> * <li>If the argument is NaN or infinite, then the result is 0.</li> * <li>If the value is already the integer value, the same value is returned</li> * </ul> * * @param value the value that needs to be rounded * @return the next larger long of the argument */ @Contract(pure = true) public static long ceil(double value) { if (!isNumber(value)) { return 0L; } long possibleValue = (long) value; if ((value - possibleValue) > 0.d) { ++possibleValue; } if (possibleValue < value) { --possibleValue; } return possibleValue; } /** * Round a float value to the next larger integer value. Special cases: * <ul> * <li>If the argument is NaN or infinite, then the result is 0.</li> * <li>If the value is already the integer value, the same value is returned</li> * </ul> * * @param value the value that needs to be rounded * @return the next larger integer of the argument */ @Contract(pure = true) public static int ceil(float value) { if (!isNumber(value)) { return 0; } if (value >= Integer.MAX_VALUE) { return Integer.MAX_VALUE; } if (value < 0.f) { return (int) value; } return (int) value + 1; } /** * Round a integer value to the next larger integer value.<br> * <b>This function throws a exception at any time because its absolutely * useless to round a integer value. This function is only implemented to * prevent useless function calls.</b> * * @param value the value that needs to be rounded * @return the next larger integer of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static int ceil(int value) { throw new OutOfCoffeeException("Rounding up a integer value? Seriously?"); } /** * Round a long value to the next larger long value.<br> * <b>This function throws a exception at any time because its absolutely * useless to round a long value. This function is only implemented to * prevent useless function calls.</b> * * @param value the value that needs to be rounded * @return the next larger long of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static long ceil(long value) { throw new OutOfCoffeeException("Rounding up a long value? Seriously?"); } /** * Round a short value to the next larger short value.<br> * <b>This function throws a exception at any time because its absolutely * useless to round a short value. This function is only implemented to * prevent useless function calls.</b> * * @param value the value that needs to be rounded * @return the next larger short of the argument */ @SuppressWarnings("unused") @Contract(value = "_ -> fail", pure = true) public static short ceil(short value) { throw new OutOfCoffeeException("Rounding up a short value? Seriously?"); } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static byte clamp(byte value, byte min, byte max) { if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } if (value <= min) { return min; } return value; } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. Special cases: * <ul> * <li>If the input value is NaN the result value will be NaN.</li> * </ul> * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static double clamp( double value, double min, double max) { if (Double.isNaN(value)) { return Double.NaN; } if (Double.isNaN(min) || Double.isNaN(max)) { throw new IllegalArgumentException("NaN is not valid value for the top and bottom border."); } if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } if (value <= min) { return min; } return value; } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. Special cases: * <ul> * <li>If the input value is NaN the result value will be NaN.</li> * </ul> * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static float clamp( float value, float min, float max) { if (Float.isNaN(value)) { return Float.NaN; } if (Float.isNaN(min) || Float.isNaN(max)) { throw new IllegalArgumentException("NaN is not valid value for the top and bottom border."); } if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } if (value <= min) { return min; } return value; } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static int clamp(int value, int min, int max) { if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } if (value <= min) { return min; } return value; } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. * * @param value the value that is put into the limits * @param range the range that defines the maximal and the minimal value * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static int clamp(int value, @Nonnull Range range) { return clamp(value, range.getMin(), range.getMax()); } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static long clamp(long value, long min, long max) { if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } if (value <= min) { return min; } return value; } /** * Limit a value within set borders. In case the value is larger then the * maximum value the maximum value is returned. In case the value is smaller * then the minimum value, the minimum value is returned. Otherwise the * input value is returned. * * @param value the value that is put into the limits * @param min the minimal allowed value, its not allowed to set NaN here * @param max the maximal allowed value, its not allowed to set NaN here * @return the input value clamped between the minimal and the maximal * allowed value */ @Contract(pure = true) public static short clamp( short value, short min, short max) { if (max < min) { throw new IllegalArgumentException("Minimal value must not be greater then the maximal value."); } if (value >= max) { return max; } else { return (value <= min) ? min : value; } } /** * These functions shall produce a value with the magnitude of x and the * sign of y. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static byte copySign(byte magnitude, byte sign) { if (((magnitude < 0) && (sign > 0)) || ((magnitude > 0) && (sign < 0))) { return (byte) -magnitude; } return magnitude; } /** * These functions shall produce a value with the magnitude of x and the * sign of y. In case either x or y are NaN the result value is NaN too. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static double copySign(double magnitude, double sign) { if (Double.isNaN(magnitude) || Double.isNaN(sign)) { return Double.NaN; } if (((magnitude < 0.d) && (sign > 0.d)) || ((magnitude > 0.d) && (sign < 0.d))) { return -magnitude; } return magnitude; } /** * These functions shall produce a value with the magnitude of x and the * sign of y. In case either x or y are NaN the result value is NaN too. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static float copySign(float magnitude, float sign) { if (Float.isNaN(magnitude) || Float.isNaN(sign)) { return Float.NaN; } if (((magnitude < 0.f) && (sign > 0.f)) || ((magnitude > 0.f) && (sign < 0.f))) { return -magnitude; } return magnitude; } /** * These functions shall produce a value with the magnitude of x and the * sign of y. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static int copySign(int magnitude, int sign) { if (((magnitude < 0) && (sign > 0)) || ((magnitude > 0) && (sign < 0))) { return -magnitude; } return magnitude; } /** * These functions shall produce a value with the magnitude of x and the * sign of y. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static long copySign(long magnitude, long sign) { if (((magnitude < 0L) && (sign > 0L)) || ((magnitude > 0L) && (sign < 0L))) { return -magnitude; } return magnitude; } /** * These functions shall produce a value with the magnitude of x and the * sign of y. * * @param magnitude the value that stores the magnitude of the result value * @param sign the value that stores the sign of the result value * @return a value with the magnitude of the argument x and the sign of the * argument y */ @Contract(pure = true) public static short copySign(short magnitude, short sign) { if (((magnitude < 0) && (sign > 0)) || ((magnitude > 0) && (sign < 0))) { return (short) -magnitude; } return magnitude; } /** * Returns cosine of a value. * * @param fValue The value to cosine, in radians. * @return the cosine of the value */ @Contract(pure = true) public static float cos(float fValue) { return sin(fValue + HALF_PI); } /** * Check if two values are equal. * * @param value1 the first value * @param value2 the second value * @return {@code true} if both values are equal */ @Contract(pure = true) public static boolean equals(int value1, int value2) { return value1 == value2; } /** * Check if two values are nearly equal. * * @param value1 the first value * @param value2 the second value * @param delta the maximal allowed difference of with values * @return <code>true<code> if the difference between both values is less * or equal then delta */ @Contract(pure = true) public static boolean equals( int value1, int value2, int delta) { return abs(value1 - value2) <= delta; } /** * Check if two values are nearly equal. * * @param value1 the first value * @param value2 the second value * @param delta the maximal allowed difference of with values * @return <code>true<code> if the difference between both values is less * or equal then delta */ @Contract(pure = true) public static boolean equals(float value1, float value2, float delta) { return abs(value1 - value2) <= delta; } /** * Returns E^fValue * * @param fValue Value to raise to a power * @return the e^fValue calculation result */ @Contract(pure = true) public static float exp(float fValue) { return (float) Math.exp(fValue); } /** * Returns a number rounded down. * * @param value The value to round * @return The given number rounded down */ @Contract(pure = true) public static long floor(double value) { if (!isNumber(value)) { return 0; } return (long) value; } /** * Returns a number rounded down. * * @param value The value to round * @return The given number rounded down */ @Contract(pure = true) public static int floor(float value) { if (!isNumber(value)) { return 0; } return (int) value; } /** * Get the inverted square root. * * @param fValue The value to process. * @return the inverted square root value of the parameter */ @Contract(pure = true) public static float invSqrt(float fValue) { return (float) (1.f / Math.sqrt(fValue)); } /** * Check if the double value is a real number. This means it not NaN and not * infinite. * * @param dValue the double value to check * @return {@code true} in case this float value is a real number */ @Contract(pure = true) public static boolean isNumber(double dValue) { return !Double.isInfinite(dValue) && !Double.isNaN(dValue); } /** * Check if the float value is a real number. This means it not NaN and not * infinite. * * @param fValue the float value to check * @return {@code true} in case this float value is a real number */ @Contract(pure = true) public static boolean isNumber(float fValue) { return !Float.isInfinite(fValue) && !Float.isNaN(fValue); } /** * Check if a number is a valid power of two. Such as the values 2, 4, 8, 16 * and so on. * * @param number The number to test. * @return {@code true} in case the number is a power of two */ @Contract(pure = true) public static boolean isPowerOfTwo(int number) { return (number > 0) && ((number & (number - 1)) == 0); } /** * Linear interpolation from startValue to endValue by the given percent. * Basically: ((1 - percent) * startValue) + (percent * endValue) * * @param percent Percent value to use. Valid values between 0.f and 1.f * @param startValue Beginning value. 0% of f * @param endValue ending value. 100% of f * @return The interpolated value between startValue and endValue. */ @Contract(pure = true) public static float LERP(float percent, float startValue, float endValue) { return ((1.f - percent) * startValue) + (percent * endValue); } /** * Returns the log base E of a value. * * @param fValue The value to log * @return The log of fValue base E */ @Contract(pure = true) public static float log(float fValue) { return (float) Math.log(fValue); } /** * Returns the logarithm of value with given base, calculated as * log(value)/log(base), so that pow(base, return)==value * * @param value The value to log * @param base Base of logarithm * @return The logarithm of value with given base */ @Contract(pure = true) public static float log(float value, float base) { return (float) (Math.log(value) / Math.log(base)); } /** * Get the next larger power of two number. * * @param number the number the search for the next larger power of two * number shall start at * @return the found power of two number */ @Contract(pure = true) public static int nearestPowerOfTwo(int number) { return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2))); } /** * Returns a random float between 0 and 1. * * @return A random float between <tt>0.0f</tt> (inclusive) to <tt>1.0f</tt> * (exclusive) */ public static float nextRandomFloat() { return RANDOM.nextFloat(); } /** * Returns a random integer value. * * @return a random integer value, every value a integer can store is * possible */ public static int nextRandomInt() { return RANDOM.nextInt(); } /** * Returns a random float between min and max * * @param min the minimal value of the random number range (inclusive) * @param max the maximal value of the random number range (exclusive) * @return the generated random number */ public static int nextRandomInt(int min, int max) { if (min == max) { return min; } if (min > max) { throw new IllegalArgumentException("The minimal value must not be larger then the maximal value."); } return RANDOM.nextInt(max - min) + min; } /** * Takes an value and expresses it in terms of min to max. * * @param val the value to normalize * @param min the bottom border of the range the value has to be in * @param max the top value of te range the value has to be in * @return the normalized value */ @Contract(pure = true) public static float normalize( float val, float min, float max) { if (Float.isInfinite(val) || Float.isNaN(val)) { return 0f; } if (Float.isInfinite(min) || Float.isNaN(min) || Float.isInfinite(max) || Float.isNaN(max)) { throw new IllegalArgumentException( "The minimal and the maximal border must not be NAN or infinite values."); } float range = max - min; if (range < FLT_EPSILON) { throw new IllegalArgumentException("Range between min and max is too small."); } float workVal = val; while (workVal > max) { workVal -= range; } while (workVal < min) { workVal += range; } return workVal; } /** * Returns a number raised to an exponent power. fBase^fExponent * * @param fBase The base value * @param fExponent The exponent value * @return base raised to exponent */ @Contract(pure = true) public static float pow(float fBase, float fExponent) { return (float) Math.pow(fBase, fExponent); } /** * Return the closest integer to the double argument. Special cases: * <ul> * <li>If the argument is NaN, the result is 0.</li> * <li>If the argument is negative infinity or any value less than or equal * to the value of Long.MIN_VALUE, the result is equal to the value of * Long.MIN_VALUE.</li> * <li>If the argument is positive infinity or any value greater than or * equal to the value of Long.MAX_VALUE, the result is equal to the value of * Long.MAX_VALUE.</li> * </ul> * * @param value the value the closest integer is needed * @return the closest integer to the argument */ @Contract(pure = true) public static long round(double value) { if (Double.isNaN(value)) { return 0; } if (value > Long.MAX_VALUE) { return Long.MAX_VALUE; } if (value < Long.MIN_VALUE) { return Long.MIN_VALUE; } return (long) (value + 0.5d); } /** * Return the closest integer to the float argument. Special cases: * <ul> * <li>If the argument is NaN, the result is 0.</li> * <li>If the argument is negative infinity or any value less than or equal * to the value of Integer.MIN_VALUE, the result is equal to the value of * Integer.MIN_VALUE.</li> * <li>If the argument is positive infinity or any value greater than or * equal to the value of Integer.MAX_VALUE, the result is equal to the value * of Integer.MAX_VALUE.</li> * </ul> * * @param value the value the closest integer is needed * @return the closest integer to the argument */ @Contract(pure = true) public static int round(float value) { if (Float.isNaN(value)) { return 0; } if (value > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } if (value < Integer.MIN_VALUE) { return Integer.MIN_VALUE; } if (value > 0.0f) { return (int) (value + 0.5f); } return (int) (value - 0.5f); } /** * Returns 1 if the number is positive, -1 if the number is negative, and 0 * otherwise * * @param fValue The float to examine * @return The float's sign */ @Contract(pure = true) public static float sign(float fValue) { return Math.signum(fValue); } /** * Returns 1 if the number is positive, -1 if the number is negative, and 0 * otherwise * * @param iValue The integer to examine * @return The integer's sign */ @Contract(pure = true) public static int sign(int iValue) { if (iValue > 0) { return 1; } if (iValue < 0) { return -1; } return 0; } /** * Returns sine of a value. * * @param fValue the value to sine, in radians. * @return the sine of the value */ @Contract(pure = true) public static float sin(float fValue) { float value = reduceSinAngle(fValue); if (abs(value) <= QUARTER_PI) { return (float) Math.sin(value); } return (float) Math.cos(HALF_PI - value); } /** * Returns the value squared. fValue ^ 2 * * @param fValue The value to square. * @return The square of the given value. */ @Contract(pure = true) public static float sqr(float fValue) { return fValue * fValue; } /** * Returns the value squared. fValue ^ 2 * * @param iValue The value to square. * @return The square of the given value. */ @Contract(pure = true) public static int sqr(int iValue) { return iValue * iValue; } /** * Returns the square root of a given value. * * @param fValue The value to square root * @return The square root of the given value */ @Contract(pure = true) public static float sqrt(float fValue) { return (float) Math.sqrt(fValue); } /** * Returns the integer square root of a integer value. It acts like * {@code (int) Math.sqrt(int)} for values lower then 289, and for * values above it returns values close to the real results. * * @param iValue the value the square root is needed from * @return the square root of the value */ @SuppressWarnings({"IfMayBeConditional", "OverlyComplexMethod"}) @Contract(pure = true) public static int sqrt(int iValue) { if (iValue >= 0x10000) { if (iValue >= 0x1000000) { if (iValue >= 0x10000000) { if (iValue >= 0x40000000) { return SQRT_TABLE[iValue >> 24] << 8; } return SQRT_TABLE[iValue >> 22] << 7; } else if (iValue >= 0x4000000) { return SQRT_TABLE[iValue >> 20] << 6; } else { return SQRT_TABLE[iValue >> 18] << 5; } } else if (iValue >= 0x100000) { if (iValue >= 0x400000) { return SQRT_TABLE[iValue >> 16] << 4; } return SQRT_TABLE[iValue >> 14] << 3; } else if (iValue >= 0x40000) { return SQRT_TABLE[iValue >> 12] << 2; } else { return SQRT_TABLE[iValue >> 10] << 1; } } if (iValue >= 0x100) { if (iValue >= 0x1000) { if (iValue >= 0x4000) { return SQRT_TABLE[iValue >> 8]; } return SQRT_TABLE[iValue >> 6] >> 1; } else if (iValue >= 0x400) { return SQRT_TABLE[iValue >> 4] >> 2; } else { return SQRT_TABLE[iValue >> 2] >> 3; } } if (iValue >= 0) { return SQRT_TABLE[iValue] >> 4; } throw new IllegalArgumentException("Can't get the square root of a negative number."); } /** * Returns the tangent of a value. * * @param fValue The value to tangent, in radians * @return The tangent of fValue */ @Contract(pure = true) public static float tan(float fValue) { return (float) Math.tan(fValue); } /** * Convert a float value from radians to degrees. * * @param radians the value in radians * @return the value in degrees */ @Contract(pure = true) public static float toDegree(float radians) { return radians * RAD_TO_DEG; } /** * Convert a float value from degrees to radians. * * @param degree the value in degrees * @return the value in radians */ @Contract(pure = true) public static float toRadians(float degree) { return degree * DEG_TO_RAD; } /** * Fast Trig functions for x86. This forces the trig function to stay within * the safe area on the x86 processor (-45 degrees to +45 degrees) The * results may be very slightly off from what the Math and StrictMath trig * functions give due to rounding in the angle reduction but it will be very * very close. * * @param radians the original angle * @return the angle within the save limits */ @Contract(pure = true) private static float reduceSinAngle(float radians) { float rad = (int) (radians / TWO_PI); // put us in -2PI to +2PI space rad = radians - (rad * TWO_PI); if (abs(rad) > PI) { // put us in -PI to +PI space rad -= TWO_PI; } if (abs(rad) > HALF_PI) {// put us in -PI/2 to +PI/2 space rad = PI - rad; } return rad; } }