Package org.kocakosm.pitaya.math

Source Code of org.kocakosm.pitaya.math.Numbers

/*----------------------------------------------------------------------------*
* This file is part of Pitaya.                                               *
* Copyright (C) 2012-2014 Osman KOCAK <kocakosm@gmail.com>                   *
*                                                                            *
* This program is free software: you can redistribute it and/or modify it    *
* under the terms of the GNU Lesser 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 Lesser General Public     *
* License for more details.                                                  *
* You should have received a copy of the GNU Lesser General Public License   *
* along with this program. If not, see <http://www.gnu.org/licenses/>.       *
*----------------------------------------------------------------------------*/

package org.kocakosm.pitaya.math;

import org.kocakosm.pitaya.util.Parameters;

import java.math.BigDecimal;

/**
* Extra math utilities.
*
* @author Osman KOCAK
*/
public final class Numbers
{
  /**
   * Returns the maximum of the given values.
   *
   * @param values a non-empty array of {@code long} values.
   *
   * @return the maximum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static long max(long... values)
  {
    Parameters.checkCondition(values.length > 0);
    long max = values[0];
    for (int i = 1; i < values.length; i++) {
      max = Math.max(max, values[i]);
    }
    return max;
  }

  /**
   * Returns the maximum of the given values.
   *
   * @param values a non-empty array of {@code int} values.
   *
   * @return the maximum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static int max(int... values)
  {
    Parameters.checkCondition(values.length > 0);
    int max = values[0];
    for (int i = 1; i < values.length; i++) {
      max = Math.max(max, values[i]);
    }
    return max;
  }

  /**
   * Returns the maximum of the given values, using the same comparison
   * rules as {@link Math#max(float, float)}.
   *
   * @param values a non-empty array of {@code float} values.
   *
   * @return the maximum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static float max(float... values)
  {
    Parameters.checkCondition(values.length > 0);
    float max = values[0];
    for (int i = 1; i < values.length; i++) {
      max = Math.max(max, values[i]);
    }
    return max;
  }

  /**
   * Returns the maximum of the given values, using the same comparison
   * rules as {@link Math#max(double, double)}.
   *
   * @param values a non-empty array of {@code double} values.
   *
   * @return the maximum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double max(double... values)
  {
    Parameters.checkCondition(values.length > 0);
    double max = values[0];
    for (int i = 1; i < values.length; i++) {
      max = Math.max(max, values[i]);
    }
    return max;
  }

  /**
   * Returns the minimum of the given values.
   *
   * @param values a non-empty array of {@code long} values.
   *
   * @return the minimum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static long min(long... values)
  {
    Parameters.checkCondition(values.length > 0);
    long min = values[0];
    for (int i = 1; i < values.length; i++) {
      min = Math.min(min, values[i]);
    }
    return min;
  }

  /**
   * Returns the minimum of the given values.
   *
   * @param values a non-empty array of {@code int} values.
   *
   * @return the minimum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static int min(int... values)
  {
    Parameters.checkCondition(values.length > 0);
    int min = values[0];
    for (int i = 1; i < values.length; i++) {
      min = Math.min(min, values[i]);
    }
    return min;
  }

  /**
   * Returns the minimum of the given values, using the same comparison
   * rules as {@link Math#min(float, float)}.
   *
   * @param values a non-empty array of {@code float} values.
   *
   * @return the minimum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static float min(float... values)
  {
    Parameters.checkCondition(values.length > 0);
    float min = values[0];
    for (int i = 1; i < values.length; i++) {
      min = Math.min(min, values[i]);
    }
    return min;
  }

  /**
   * Returns the minimum of the given values, using the same comparison
   * rules as {@link Math#min(double, double)}.
   *
   * @param values a non-empty array of {@code double} values.
   *
   * @return the minimum of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double min(double... values)
  {
    Parameters.checkCondition(values.length > 0);
    double min = values[0];
    for (int i = 1; i < values.length; i++) {
      min = Math.min(min, values[i]);
    }
    return min;
  }

  /**
   * Returns the arithmetic mean of the given values. This method is not
   * subject to overflow.
   *
   * @param values the values.
   *
   * @return the arithmetic mean of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double mean(int... values)
  {
    Parameters.checkCondition(values.length > 0);
    long sum = 0L;
    for (int value : values) {
      sum += value;
    }
    return (double) sum / values.length;
  }

  /**
   * Returns the arithmetic mean of the given values. This method is not
   * subject to overflow.
   *
   * @param values the values.
   *
   * @return the arithmetic mean of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double mean(long... values)
  {
    Parameters.checkCondition(values.length > 0);
    BigDecimal sum = BigDecimal.ZERO;
    for (long value : values) {
      sum = sum.add(BigDecimal.valueOf(value));
    }
    return sum.divide(BigDecimal.valueOf(values.length)).doubleValue();
  }

  /**
   * Returns the arithmetic mean of the given values. This method is not
   * subject to overflow.
   *
   * @param values the values.
   *
   * @return the arithmetic mean of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double mean(double... values)
  {
    Parameters.checkCondition(values.length > 0);
    BigDecimal sum = BigDecimal.ZERO;
    for (double value : values) {
      sum = sum.add(BigDecimal.valueOf(value));
    }
    return sum.divide(BigDecimal.valueOf(values.length)).doubleValue();
  }

  /**
   * Returns the arithmetic mean of the given values. This method is not
   * subject to overflow.
   *
   * @param values the values.
   *
   * @return the arithmetic mean of the given values.
   *
   * @throws NullPointerException if {@code values} is {@code null}.
   * @throws IllegalArgumentException if {@code values} is empty.
   */
  public static double mean(float... values)
  {
    Parameters.checkCondition(values.length > 0);
    BigDecimal sum = BigDecimal.ZERO;
    for (float value : values) {
      sum = sum.add(BigDecimal.valueOf(value));
    }
    return sum.divide(BigDecimal.valueOf(values.length)).doubleValue();
  }

  /**
   * Returns whether the given value is a real value. Namely, it returns
   * {@code false} if the given value is infinite or NaN, and {@code true}
   * in all other cases.
   *
   * @param f the value to test.
   *
   * @return whether the given value is a real value.
   */
  public static boolean isFinite(float f)
  {
    return !Float.isInfinite(f) && !Float.isNaN(f);
  }

  /**
   * Returns whether the given value is a real value. Namely, it returns
   * {@code false} if the given value is infinite or NaN, and {@code true}
   * in all other cases.
   *
   * @param d the value to test.
   *
   * @return whether the given value is a real value.
   */
  public static boolean isFinite(double d)
  {
    return !Double.isInfinite(d) && !Double.isNaN(d);
  }

  /**
   * Returns the absolute value of the given value, provided the result
   * fits into a {@code long}.
   *
   * @param a the value.
   *
   * @return the absolute value of {@code a}.
   *
   * @throws ArithmeticException if the absolute value of {@code a} can't
   *  be represented by a {@code long}.
   */
  public static long safeAbs(long a)
  {
    if (a == Long.MIN_VALUE) {
      throw new ArithmeticException(
        "Long overflow: abs(" + a + ")");
    }
    return Math.abs(a);
  }

  /**
   * Returns the absolute value of the given value, provided the result
   * fits into an {@code int}.
   *
   * @param a the value.
   *
   * @return the absolute value of {@code a}.
   *
   * @throws ArithmeticException if the absolute value of {@code a} can't
   *  be represented by a {@code int}.
   */
  public static int safeAbs(int a)
  {
    if (a == Integer.MIN_VALUE) {
      throw new ArithmeticException(
        "Int overflow: abs(" + a + ")");
    }
    return Math.abs(a);
  }

  /**
   * Returns the opposite of the given value, provided the result fits
   * into a {@code long}.
   *
   * @param a the value to negate.
   *
   * @return {@code -a}.
   *
   * @throws ArithmeticException if {@code -a} can't be represented by a
   *  {@code long}.
   */
  public static long safeNegate(long a)
  {
    if (a == Long.MIN_VALUE) {
      throw new ArithmeticException("Long overflow: -" + a);
    }
    return -a;
  }

  /**
   * Returns the opposite of the given value, provided the result fits
   * into an {@code int}.
   *
   * @param a the value to negate.
   *
   * @return {@code -a}.
   *
   * @throws ArithmeticException if {@code -a} can't be represented by an
   *  {@code int}.
   */
  public static int safeNegate(int a)
  {
    if (a == Integer.MIN_VALUE) {
      throw new ArithmeticException("Int overflow: -" + a);
    }
    return -a;
  }

  /**
   * Returns the sum of {@code a} and {@code b}, provided the result fits
   * into a {@code long}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a + b}.
   *
   * @throws ArithmeticException if {@code a + b} can't be represented by
   *  a {@code long}.
   */
  public static long safeAdd(long a, long b)
  {
    long sum = a + b;
    if (a < 0L != sum < 0L && a < 0L == b < 0L) {
      throw new ArithmeticException(
        "Long overflow: " + a + " + " + b);
    }
    return sum;
  }

  /**
   * Returns the sum of {@code a} and {@code b}, provided the result fits
   * into an {@code int}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a + b}.
   *
   * @throws ArithmeticException if {@code a + b} can't be represented by
   *  an {@code int}.
   */
  public static int safeAdd(int a, int b)
  {
    int sum = a + b;
    if (a < 0 != sum < 0 && a < 0 == b < 0) {
      throw new ArithmeticException(
        "Int overflow: " + a + " + " + b);
    }
    return sum;
  }

  /**
   * Returns the difference of {@code a} and {@code b}, provided the
   * result fits into a {@code long}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a - b}.
   *
   * @throws ArithmeticException if {@code a - b} can't be represented by
   *  a {@code long}.
   */
  public static long safeSubtract(long a, long b)
  {
    long diff = a - b;
    if (a < 0L != diff < 0L && a < 0L != b < 0L) {
      throw new ArithmeticException(
        "Long overflow: " + a + " - " + b);
    }
    return diff;
  }

  /**
   * Returns the difference of {@code a} and {@code b}, provided the
   * result fits into an {@code int}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a - b}.
   *
   * @throws ArithmeticException if {@code a - b} can't be represented by
   *  an {@code int}.
   */
  public static int safeSubtract(int a, int b)
  {
    int diff = a - b;
    if (a < 0 != diff < 0 && a < 0 != b < 0) {
      throw new ArithmeticException(
        "Int overflow: " + a + " - " + b);
    }
    return diff;
  }

  /**
   * Returns the product of {@code a} and {@code b}, provided the result
   * fits into into a {@code long}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a * b}.
   *
   * @throws ArithmeticException if {@code a * b} can't be represented by
   *  a {@code long}.
   */
  public static long safeMultiply(long a, long b)
  {
    if (a == 0L || b == 0L) {
      return 0L;
    }
    long max = a < 0L == b < 0L ? Long.MAX_VALUE : Long.MIN_VALUE;
    if ((b > 0L && b > max / a) || (b < 0L && b < max / a)) {
      throw new ArithmeticException(
        "Long overflow: " + a + " * " + b);
    }
    return a * b;
  }

  /**
   * Returns the product of {@code a} and {@code b}, provided the result
   * fits into into an {@code int}.
   *
   * @param a the first operand.
   * @param b the second operand.
   *
   * @return {@code a * b}.
   *
   * @throws ArithmeticException if {@code a * b} can't be represented by
   *  an {@code int}.
   */
  public static int safeMultiply(int a, int b)
  {
    if (a == 0 || b == 0) {
      return 0;
    }
    long max = a < 0 == b < 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
    if ((b > 0 && b > max / a) || (b < 0 && b < max / a)) {
      throw new ArithmeticException(
        "Int overflow: " + a + " * " + b);
    }
    return a * b;
  }

  /**
   * Returns the result of the integer division of the first number by the
   * second, provided the result fits into a {@code long}.
   *
   * @param a the dividend.
   * @param b the divisor.
   *
   * @return {@code a / b}.
   *
   * @throws ArithmeticException if {@code b} is equal to {@code 0} or if
   *  {@code a / b} can't be represented by a {@code long}.
   */
  public static long safeDivide(long a, long b)
  {
    if (a == Long.MIN_VALUE && b == -1L) {
      throw new ArithmeticException(
        "Long overflow: " + a + " / " + b);
    }
    return a / b;
  }

  /**
   * Returns the result of the integer division of the first number by the
   * second, provided the result fits into an {@code int}.
   *
   * @param a the dividend.
   * @param b the divisor.
   *
   * @return {@code a / b}.
   *
   * @throws ArithmeticException if {@code b} is equal to {@code 0} or if
   *  {@code a / b} can't be represented by an {@code int}.
   */
  public static int safeDivide(int a, int b)
  {
    if (a == Integer.MIN_VALUE && b == -1L) {
      throw new ArithmeticException(
        "Int overflow: " + a + " / " + b);
    }
    return a / b;
  }

  /**
   * Returns the value of the first argument raised to the power of the
   * second, provided the result fits into a {@code long}. This method
   * implements the exponentiation by squaring method. Please refer to
   * <a href="http://en.wikipedia.org/wiki/Exponentiation_by_squaring">
   * Wikipedia</a> for further information.
   *
   * @param a the base.
   * @param b the exponent.
   *
   * @return {@code a ^ b}.
   *
   * @throws IllegalArgumentException if {@code b < 0}.
   * @throws ArithmeticException if {@code a ^ b} can't be represented by
   *  a {@code long}.
   */
  public static long safePow(long a, int b)
  {
    Parameters.checkCondition(b >= 0);
    if (b == 0) {
      return 1L;
    }
    long base = a;
    int exponent = b;
    long result = 1L;
    try {
      while (exponent > 1) {
        if ((exponent & 1) != 0) {
          result = safeMultiply(result, base);
          exponent -= 1;
        }
        base = safeMultiply(base, base);
        exponent >>= 1;
      }
      return safeMultiply(result, base);
    } catch (ArithmeticException e) {
      throw new ArithmeticException(
        "Long overflow: " + a + " ^ " + b);
    }
  }

  /**
   * Returns the value of the first argument raised to the power of the
   * second, provided the result fits into an {@code int}. This method
   * implements the exponentiation by squaring method. Please refer to
   * <a href="http://en.wikipedia.org/wiki/Exponentiation_by_squaring">
   * Wikipedia</a> for further information.
   *
   * @param a the base.
   * @param b the exponent.
   *
   * @return {@code a ^ b}.
   *
   * @throws IllegalArgumentException if {@code b < 0}.
   * @throws ArithmeticException if {@code a ^ b} can't be represented by
   *  an {@code int}.
   */
  public static int safePow(int a, int b)
  {
    Parameters.checkCondition(b >= 0);
    if (b == 0) {
      return 1;
    }
    int base = a;
    int exponent = b;
    int result = 1;
    try {
      while (exponent > 1) {
        if ((exponent & 1) != 0) {
          result = safeMultiply(result, base);
          exponent -= 1;
        }
        base = safeMultiply(base, base);
        exponent >>= 1;
      }
      return safeMultiply(result, base);
    } catch (ArithmeticException e) {
      throw new ArithmeticException(
        "Int overflow: " + a + " ^ " + b);
    }
  }

  /**
   * Returns the greatest common divisor of the absolute value of the
   * given two numbers. This method first computes the absolute values of
   * the given numbers, thus it doesn't accept {@code Long.MIN_VALUE}.
   * Also, note that if one of the given values is {@code 0}, this method
   * will return the absolute value of the second argument.
   * This method implements the binary GCD algorithm (also known as
   * Stein's algorithm). For further information on this algorithm, please
   * refer to <a href="http://en.wikipedia.org/wiki/Binary_GCD_algorithm">
   * Wikipedia</a>.
   *
   * @param a the first number.
   * @param b the second number.
   *
   * @return the greatest common divisor of {@code a} and {@code b}.
   *
   * @throws ArithmeticException if {@code a} or {@code b} is equal to
   *  {@code Long.MIN_VALUE}.
   */
  public static long gcd(long a, long b)
  {
    if (a < 0L || b < 0L) {
      return gcd(safeAbs(a), safeAbs(b));
    }
    if (a == 0L) {
      return b;
    }
    if (b == 0L) {
      return a;
    }
    int shift = 0;
    while (((a | b) & 1L) == 0) {
      a >>= 1;
      b >>= 1;
      shift++;
    }
    while ((a & 1L) == 0L) {
      a >>= 1;
    }
    do {
      while ((b & 1L) == 0L) {
        b >>= 1;
      }
      if (a > b) {
        long tmp = b;
        b = a;
        a = tmp;
      }
      b -= a;
    } while (b != 0L);
    return a << shift;
  }

  /**
   * Returns the greatest common divisor of the absolute value of the
   * given two numbers. This method first computes the absolute values of
   * the given numbers, thus it doesn't accept {@code Integer.MIN_VALUE}.
   * Also, note that if one of the given values is {@code 0}, this method
   * will return the absolute value of the second argument.
   * This method implements the binary GCD algorithm (also known as
   * Stein's algorithm). For further information on this algorithm, please
   * refer to <a href="http://en.wikipedia.org/wiki/Binary_GCD_algorithm">
   * Wikipedia</a>.
   *
   * @param a the first number.
   * @param b the second number.
   *
   * @return the greatest common divisor of {@code a} and {@code b}.
   *
   * @throws ArithmeticException if {@code a} or {@code b} is equal to
   *  {@code Integer.MIN_VALUE}.
   */
  public static int gcd(int a, int b)
  {
    if (a < 0 || b < 0) {
      return gcd(safeAbs(a), safeAbs(b));
    }
    return (int) gcd((long) a, (long) b);
  }

  /**
   * Returns the least common multiple of the absolute value of the given
   * two numbers. This method first computes the absolute values of the
   * given numbers, thus it doesn't accept {@code Long.MIN_VALUE}. Also,
   * note that if one of the given values is {@code 0}, this method will
   * return the absolute value of the second argument. This method uses
   * the formula {@code lcm(a,b) = (a / gcd(a,b)) * b}. Please refer to
   * <a href="http://en.wikipedia.org/wiki/Least_common_multiple">
   * Wikipedia</a> for further information.
   *
   * @param a the first number.
   * @param b the second number.
   *
   * @return the least common multiple of {@code a} and {@code b}.
   *
   * @throws ArithmeticException if {@code a} or {@code b} is equal to
   *  {@code Long.MIN_VALUE}.
   */
  public static long lcm(long a, long b)
  {
    try {
      if (a < 0L || b < 0L) {
        return lcm(safeAbs(a), safeAbs(b));
      }
      if (a == 0L) {
        return b;
      }
      if (b == 0L) {
        return a;
      }
      return safeMultiply(a / gcd(a, b), b);
    } catch (ArithmeticException e) {
      throw new ArithmeticException(
        "Long overflow: lcm(" + a + ", " + b + ")");
    }
  }

  /**
   * Returns the least common multiple of the absolute value of the given
   * two numbers. This method first computes the absolute values of the
   * given numbers, thus it doesn't accept {@code Integer.MIN_VALUE}.
   * Also, note that if one of the given values is {@code 0}, this method
   * will return the absolute value of the second argument. This method
   * uses the formula {@code lcm(a,b) = (a / gcd(a,b)) * b}. Please refer
   * to <a href="http://en.wikipedia.org/wiki/Least_common_multiple">
   * Wikipedia</a> for further information.
   *
   * @param a the first number.
   * @param b the second number.
   *
   * @return the least common multiple of {@code a} and {@code b}.
   *
   * @throws ArithmeticException if {@code a} or {@code b} is equal to
   *  {@code Integer.MIN_VALUE}.
   */
  public static int lcm(int a, int b)
  {
    try {
      if (a < 0 || b < 0) {
        return lcm(safeAbs(a), safeAbs(b));
      }
      if (a == 0) {
        return b;
      }
      if (b == 0) {
        return a;
      }
      return safeMultiply(a / gcd(a, b), b);
    } catch (ArithmeticException e) {
      throw new ArithmeticException(
        "Int overflow: lcm(" + a + ", " + b + ")");
    }
  }

  /**
   * Casts the given {@code long} value to {@code int}, if possible.
   *
   * @param a the value to cast to {@code int}.
   *
   * @return the casted value.
   *
   * @throws ArithmeticException if {@code a} cannot be cast into an
   *  {@code int}.
   */
  public static int safeToInt(long a)
  {
    if (a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE) {
      return (int) a;
    }
    throw new ArithmeticException(a + " can't be cast to int");
  }

  private Numbers()
  {
    /* ... */
  }
TOP

Related Classes of org.kocakosm.pitaya.math.Numbers

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.