content: /*******************************************************************************
   * Copyright 2011 See AUTHORS file.
   *
   * Licensed 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 com.badlogic.gdx.math;
  
  import java.util.Random;
  
  /** Utility and fast math functions.
   * <p>
   * Thanks to Riven on JavaGaming.org for the basis of sin/cos/floor/ceil.
   * @author Nathan Sweet */
  public final class MathUtils {
      static public final float nanoToSec = 1 / 1000000000f;
  
      // ---
      static public final float FLOAT_ROUNDING_ERROR = 0.000001f; // 32 bits
      static public final float PI = 3.1415927f;
      static public final float PI2 = PI * 2;
  
      static public final float E = 2.7182818f;
  
      static private final int SIN_BITS = 14; // 16KB. Adjust for accuracy.
      static private final int SIN_MASK = ~(-1 << SIN_BITS);
      static private final int SIN_COUNT = SIN_MASK + 1;
  
      static private final float radFull = PI * 2;
      static private final float degFull = 360;
      static private final float radToIndex = SIN_COUNT / radFull;
      static private final float degToIndex = SIN_COUNT / degFull;
  
      /** multiply by this to convert from radians to degrees */
      static public final float radiansToDegrees = 180f / PI;
      static public final float radDeg = radiansToDegrees;
      /** multiply by this to convert from degrees to radians */
      static public final float degreesToRadians = PI / 180;
      static public final float degRad = degreesToRadians;
  
      static private class Sin {
          static final float[] table = new float[SIN_COUNT];
  
          static {
              for (int i = 0; i < SIN_COUNT; i++)
                  table[i] = (float) Math.sin((i + 0.5f) / SIN_COUNT * radFull);
              for (int i = 0; i < 360; i += 90)
                  table[(int)(i * degToIndex) & SIN_MASK] = (float) Math.sin(i * degreesToRadians);
          }
      }
  
      /** Returns the sine in radians from a lookup table. */
      static public float sin (float radians) {
          return Sin.table[(int)(radians * radToIndex) & SIN_MASK];
      }
  
      /** Returns the cosine in radians from a lookup table. */
      static public float cos (float radians) {
          return Sin.table[(int)((radians + PI / 2) * radToIndex) & SIN_MASK];
      }
  
      /** Returns the sine in radians from a lookup table. */
      static public float sinDeg (float degrees) {
          return Sin.table[(int)(degrees * degToIndex) & SIN_MASK];
      }
  
      /** Returns the cosine in radians from a lookup table. */
      static public float cosDeg (float degrees) {
          return Sin.table[(int)((degrees + 90) * degToIndex) & SIN_MASK];
      }
  
      // ---
  
      /** Returns atan2 in radians, faster but less accurate than Math.atan2. Average error of 0.00231 radians (0.1323 degrees),
       * largest error of 0.00488 radians (0.2796 degrees). */
      static public float atan2 (float y, float x) {
          if (x == 0f) {
              if (y > 0f) return PI / 2;
              if (y == 0f) return 0f;
              return -PI / 2;
          }
          final float atan, z = y / x;
          if (Math.abs(z) < 1f) {
              atan = z / (1f + 0.28f * z * z);
              if (x < 0f) return atan + (y < 0f ? -PI : PI);
              return atan;
          }
          atan = PI / 2 - z / (z * z + 0.28f);
          return y < 0f ? atan - PI : atan;
      }
  
      // ---
  
      static public Random random = new Random();
  
      /** Returns a random number between 0 (inclusive) and the specified value (inclusive). */
      static public int random (int range) {
          return random.nextInt(range + 1);
      }
  
      /** Returns a random number between start (inclusive) and end (inclusive). */
      static public int random (int start, int end) {
          return start + random.nextInt(end - start + 1);
      }
  
      /** Returns a random number between 0 (inclusive) and the specified value (inclusive). */
      static public long random (long range) {
          return (long)(random.nextDouble() * range);
      }
  
      /** Returns a random number between start (inclusive) and end (inclusive). */
      static public long random (long start, long end) {
          return start + (long)(random.nextDouble() * (end - start));
      }
  
      /** Returns a random boolean value. */
      static public boolean randomBoolean () {
          return random.nextBoolean();
      }
  
      /** Returns true if a random value between 0 and 1 is less than the specified value. */
      static public boolean randomBoolean (float chance) {
          return MathUtils.random() < chance;
      }
  
      /** Returns random number between 0.0 (inclusive) and 1.0 (exclusive). */
      static public float random () {
          return random.nextFloat();
      }
  
      /** Returns a random number between 0 (inclusive) and the specified value (exclusive). */
      static public float random (float range) {
          return random.nextFloat() * range;
      }
  
      /** Returns a random number between start (inclusive) and end (exclusive). */
      static public float random (float start, float end) {
          return start + random.nextFloat() * (end - start);
      }
  
      /** Returns -1 or 1, randomly. */
      static public int randomSign () {
          return 1 | (random.nextInt() >> 31);
      }
  
      /** Returns a triangularly distributed random number between -1.0 (exclusive) and 1.0 (exclusive), where values around zero are
       * more likely.
       * <p>
       * This is an optimized version of {@link #randomTriangular(float, float, float) randomTriangular(-1, 1, 0)} */
      public static float randomTriangular () {
          return random.nextFloat() - random.nextFloat();
      }
  
      /** Returns a triangularly distributed random number between {@code -max} (exclusive) and {@code max} (exclusive), where values
       * around zero are more likely.
       * <p>
       * This is an optimized version of {@link #randomTriangular(float, float, float) randomTriangular(-max, max, 0)}
       * @param max the upper limit */
      public static float randomTriangular (float max) {
          return (random.nextFloat() - random.nextFloat()) * max;
      }
  
      /** Returns a triangularly distributed random number between {@code min} (inclusive) and {@code max} (exclusive), where the
       * {@code mode} argument defaults to the midpoint between the bounds, giving a symmetric distribution.
       * <p>
       * This method is equivalent of {@link #randomTriangular(float, float, float) randomTriangular(min, max, (min + max) * .5f)}
       * @param min the lower limit
       * @param max the upper limit */
      public static float randomTriangular (float min, float max) {
          return randomTriangular(min, max, (min + max) * 0.5f);
      }
  
      /** Returns a triangularly distributed random number between {@code min} (inclusive) and {@code max} (exclusive), where values
       * around {@code mode} are more likely.
       * @param min the lower limit
       * @param max the upper limit
       * @param mode the point around which the values are more likely */
      public static float randomTriangular (float min, float max, float mode) {
          float u = random.nextFloat();
          float d = max - min;
          if (u <= (mode - min) / d) return min + (float) Math.sqrt(u * d * (mode - min));
          return max - (float) Math.sqrt((1 - u) * d * (max - mode));
      }
  
      // ---
  
      /** Returns the next power of two. Returns the specified value if the value is already a power of two. */
      static public int nextPowerOfTwo (int value) {
          if (value == 0) return 1;
          value--;
          value |= value >> 1;
          value |= value >> 2;
          value |= value >> 4;
          value |= value >> 8;
          value |= value >> 16;
          return value + 1;
      }
  
      static public boolean isPowerOfTwo (int value) {
          return value != 0 && (value & value - 1) == 0;
      }
  
      // ---
  
      static public short clamp (short value, short min, short max) {
          if (value < min) return min;
          if (value > max) return max;
          return value;
      }
  
      static public int clamp (int value, int min, int max) {
          if (value < min) return min;
          if (value > max) return max;
          return value;
      }
  
      static public long clamp (long value, long min, long max) {
          if (value < min) return min;
          if (value > max) return max;
          return value;
      }
  
      static public float clamp (float value, float min, float max) {
          if (value < min) return min;
          if (value > max) return max;
          return value;
      }
  
      static public double clamp (double value, double min, double max) {
          if (value < min) return min;
          if (value > max) return max;
          return value;
      }
  
      // ---
  
      /** Linearly interpolates between fromValue to toValue on progress position. */
      static public float lerp (float fromValue, float toValue, float progress) {
          return fromValue + (toValue - fromValue) * progress;
      }
  
      /** Linearly interpolates between two angles in radians. Takes into account that angles wrap at two pi and always takes the
       * direction with the smallest delta angle.
       *
       * @param fromRadians start angle in radians
       * @param toRadians target angle in radians
       * @param progress interpolation value in the range [0, 1]
       * @return the interpolated angle in the range [0, PI2[ */
      public static float lerpAngle (float fromRadians, float toRadians, float progress) {
          float delta = ((toRadians - fromRadians + PI2 + PI) % PI2) - PI;
          return (fromRadians + delta * progress + PI2) % PI2;
      }
  
      /** Linearly interpolates between two angles in degrees. Takes into account that angles wrap at 360 degrees and always takes
       * the direction with the smallest delta angle.
       *
       * @param fromDegrees start angle in degrees
       * @param toDegrees target angle in degrees
       * @param progress interpolation value in the range [0, 1]
       * @return the interpolated angle in the range [0, 360[ */
      public static float lerpAngleDeg (float fromDegrees, float toDegrees, float progress) {
          float delta = ((toDegrees - fromDegrees + 360 + 180) % 360) - 180;
          return (fromDegrees + delta * progress + 360) % 360;
      }
  
      // ---
  
      static private final int BIG_ENOUGH_INT = 16 * 1024;
      static private final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT;
      static private final double CEIL = 0.9999999;
      static private final double BIG_ENOUGH_CEIL = 16384.999999999996;
      static private final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5f;
  
      /** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats from
       * -(2^14) to (Float.MAX_VALUE - 2^14). */
      static public int floor (float value) {
          return (int)(value + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT;
      }
  
      /** Returns the largest integer less than or equal to the specified float. This method will only properly floor floats that are
       * positive. Note this method simply casts the float to int. */
      static public int floorPositive (float value) {
          return (int)value;
      }
  
      /** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats from
       * -(2^14) to (Float.MAX_VALUE - 2^14). */
      static public int ceil (float value) {
          return BIG_ENOUGH_INT - (int)(BIG_ENOUGH_FLOOR - value);
      }
  
      /** Returns the smallest integer greater than or equal to the specified float. This method will only properly ceil floats that
       * are positive. */
      static public int ceilPositive (float value) {
          return (int)(value + CEIL);
      }
  
      /** Returns the closest integer to the specified float. This method will only properly round floats from -(2^14) to
       * (Float.MAX_VALUE - 2^14). */
      static public int round (float value) {
          return (int)(value + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;
      }
  
      /** Returns the closest integer to the specified float. This method will only properly round floats that are positive. */
      static public int roundPositive (float value) {
          return (int)(value + 0.5f);
      }
  
      /** Returns true if the value is zero (using the default tolerance as upper bound) */
      static public boolean isZero (float value) {
          return Math.abs(value) <= FLOAT_ROUNDING_ERROR;
      }
  
      /** Returns true if the value is zero.
       * @param tolerance represent an upper bound below which the value is considered zero. */
      static public boolean isZero (float value, float tolerance) {
          return Math.abs(value) <= tolerance;
      }
  
      /** Returns true if a is nearly equal to b. The function uses the default floating error tolerance.
       * @param a the first value.
       * @param b the second value. */
      static public boolean isEqual (float a, float b) {
          return Math.abs(a - b) <= FLOAT_ROUNDING_ERROR;
      }
  
      /** Returns true if a is nearly equal to b.
       * @param a the first value.
       * @param b the second value.
       * @param tolerance represent an upper bound below which the two values are considered equal. */
      static public boolean isEqual (float a, float b, float tolerance) {
          return Math.abs(a - b) <= tolerance;
      }
  
      /** @return the logarithm of value with base a */
      static public float log (float a, float value) {
          return (float)(Math.log(value) / Math.log(a));
      }
  
      /** @return the logarithm of value with base 2 */
      static public float log2 (float value) {
          return log(2, value);
      }
  }