All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cp.elements.lang.MathUtils Maven / Gradle / Ivy

/*
 * Copyright 2011-Present Author or Authors.
 *
 * 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 org.cp.elements.lang;

import java.math.BigInteger;

import org.cp.elements.lang.annotation.NotNull;
import org.cp.elements.lang.annotation.NullSafe;

/**
 * {@link MathUtils} is an abstract utility class encapsulating common mathematical operations and calculations.
 *
 * @author John J. Blum
 * @see java.lang.Math
 * @see java.math.BigInteger
 * @see math.com
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public abstract class MathUtils {

  public static final double BASE_TEN = 10.0d;
  public static final double BASE_TWO = 2.0d;

  public static final BigInteger NEGATIVE_ONE = BigInteger.ONE.negate();
  public static final BigInteger TWO = BigInteger.valueOf(2);

  protected static final String DECIMAL_POINT = StringUtils.DOT_SEPARATOR;
  protected static final String NUMBER_LESS_THAN_ZERO_ERROR_MESSAGE = "Value [%d] must be greater than equal to 0";

  /**
   * Calculates the area of a circle.
   *
   * {@literal A = π * radius^2}.
   *
   * @param radius {@link Double value} declaring the radius of the circle.
   * @return the area of a circle having the given radius.
   * @see #ellipseArea(double, double)
   */
  public static double circleArea(double radius) {
    return ellipseArea(radius, radius);
  }

  /**
   * Calculates the circumference of a circle.
   *
   * {@literal C = 2πr = 2 * π * radius}.
   *
   * @param radius {@link Double value} declaring the radius of the circle.
   * @return the circumference of a circle having the given radius.
   * @see java.lang.Math#PI
   */
  public static double circleCircumference(double radius) {
    return 2.0d * Math.PI * radius;
  }

  /**
   * Calculates the diameter of a circle.
   *
   * {@literal C = 2r = 2 * radius}.
   *
   * @param radius {@link Double value} declaring the radius of the circle.
   * @return the diameter of a circle having the given radius.
   */
  public static double circleDiameter(double radius) {
    return 2.0d * radius;
  }

  /**
   * Calculates the volume of a cone.
   *
   * {@literal V = π * radius^2 * height / 3.0}.
   *
   * @param radius {@link Double value} declaring the radius of the cone's base.
   * @param height {@link Double value} declaring the height of the cone.
   * @return the volume of a cone having the given radius and height.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#PI
   */
  public static double coneVolume(double radius, double height) {
    return Math.PI * Math.pow(radius, 2) * height / 3.0d;
  }

  /**
   * Counts the number of decimal places in the given {@link Double value}.
   *
   * @param value {@link Double value} for which to count the number of decimal places.
   * @return a count of the number of decimal places in the given {@link Double value}.
   */
  public static int countNumberOfDecimalPlaces(double value) {

    String stringValue = String.valueOf(value);
    int indexOfDecimalPoint = stringValue.indexOf(DECIMAL_POINT);

    return StringUtils.getDigits(stringValue.substring(indexOfDecimalPoint)).length();
  }

  /**
   * Calculates the surface area of a cube.
   *
   * {@literal A = 6.0 * sideLength^2}.
   *
   * @param sideLength {@link Double value} declaring the length of a side in the cube.
   * @return the surface area of a cube having the given side length.
   * @see #squareArea(double)
   */
  public static double cubeSurfaceArea(double sideLength) {
    return 6.0d * squareArea(sideLength);
  }

  /**
   * Calculates the volume of a cube.
   *
   * {@literal A = sideLength^3}.
   *
   * @param sideLength {@link Double value} declaring the length of a side in the cube.
   * @return the volume of a cube having the given side length.
   * @see java.lang.Math#pow(double, double)
   */
  public static double cubeVolume(double sideLength) {
    return Math.pow(sideLength, 3);
  }

  /**
   * Calculates the surface area of a cylinder.
   *
   * {@literal A = 2πrh + 2πr^2 = 2 * π * radius * height + 2 * π * radius^2}.
   *
   * @param radius {@link Double value} declaring the radius of the cylinder.
   * @param height {@link Double value} declaring the height of the cylinder.
   * @return the surface area of a cylinder having the given radius and height.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#PI
   */
  public static double cylinderSurfaceArea(double radius, double height) {
    return (2.0d * Math.PI * Math.pow(radius, 2)) + (2.0d * Math.PI * radius * height);
  }

  /**
   * Calculates the volume of a cylinder.
   *
   * {@literal V = πr^2h = π * radius^2 * height}.
   *
   * @param radius {@link Double value} declaring the radius of the cylinder's end(s).
   * @param height {@link Double value} declaring the height of the cylinder.
   * @return the volume of a cylinder having the given radius and height.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#PI
   */
  public static double cylinderVolume(double radius, double height) {
    return Math.PI * Math.pow(radius, 2) * height;
  }

  /**
   * Calculates the area of an ellipse.
   *
   * {@literal A = πab = π * length radius * height radius}.
   *
   * @param lengthRadius {@link Double value} declaring the (length) radius of the ellipse (x-axis).
   * @param heightRadius {@link Double value} declaring the (height) radius of the ellipse (y-axis).
   * @return the area of an ellipse having given the length (x) and height (y) radius.
   * @see java.lang.Math#PI
   */
  public static double ellipseArea(double lengthRadius, double heightRadius) {
    return Math.PI * lengthRadius * heightRadius;
  }

  /**
   * Calculates the volume of an ellipse.
   *
   * {@literal V = 4/3 * π * A * B * C}, Where A, B and C are the length (x-axis), height (y-axis) and width (z-axis)
   * radius values from the center reaching out to the surface of the ellipsoid in 3D space.
   *
   * @param lengthRadius {@link Double value} declaring the length radius of the ellipse (x-axis).
   * @param heightRadius {@link Double value} declaring the height radius of the ellipse (y-axis).
   * @param widthRadius {@link Double value} declaring the width radius of the ellipse (z-axis).
   * @return the volume of the ellipse having the given length, height and width radius.
   * @see java.lang.Math#PI
   */
  public static double ellipseVolume(double lengthRadius, double heightRadius, double widthRadius) {
    return 4.0d * Math.PI * lengthRadius * heightRadius * widthRadius / 3.0d;
  }

  /**
   * Calculates the area of a equilateral triangle.
   *
   * {@literal A = sqrt(3.0) / 4.0 * sideLength^2}.
   *
   * @param sideLength {@link Double value} declaring the length of a side in the equilateral triangle.
   * @return the area of an equilateral triangle having the given length of a side.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#sqrt(double)
   */
  public static double equilateralTriangleArea(double sideLength) {
    return Math.sqrt(3.0d) / 4.0d * Math.pow(sideLength, 2);
  }

  /**
   * Calculates the factorial of the given number using an iterative algorithm and {@link BigInteger} value type
   * to avoid a {@literal StackOverflowException} and numeric overflow, respectively.
   *
   * @param value {@link BigInteger value} used to compute the factorial.
   * @return the factorial of the given {@link BigInteger number}.
   * @throws java.lang.IllegalArgumentException if the {@link BigInteger number} is {@literal null}
   * or less than {@literal 0}.
   * @see java.math.BigInteger
   */
  public static @NotNull BigInteger factorial(@NotNull BigInteger value) {

    Assert.notNull(value, "Value to compute the factorial of is required");
    Assert.isTrue(value.compareTo(BigInteger.ZERO) >= 0, NUMBER_LESS_THAN_ZERO_ERROR_MESSAGE, value);

    if (value.compareTo(TWO) <= 0) {
      return value.equals(TWO) ? TWO : BigInteger.ONE;
    }

    BigInteger result = value;
    BigInteger multiplier = value;

    for (multiplier = multiplier.add(NEGATIVE_ONE); multiplier.compareTo(BigInteger.ONE) > 0;
          multiplier = multiplier.add(NEGATIVE_ONE)) {

      result = result.multiply(multiplier);
    }

    return result;
  }

  /**
   * Gets the {@literal Fibonacci number} at {@link Integer position n} in the {@literal Fibonacci Sequence}.
   *
   * @param n {@link Integer value} declaring the {@literal nth number} in the {@literal Fibonacci Sequence}.
   * @return the {@link Integer nth number} in the {@literal Fibonacci Sequence}.
   * @throws IllegalArgumentException if position (n) is less than {@literal 1}.
   * @see #fibonacciSequence(int)
   */
  public static int fibonacciNumber(int n) {
    return fibonacciSequence(n)[n - 1];
  }

  /**
   * Calculates the {@literal Fibonacci Sequence} to the {@link Integer nth position}.
   *
   * @param n {@link Integer value} declaring the number of {@literal Fibonacci numbers}
   * in the {@literal Fibonacci Sequence} to calculate.
   * @return an {@link Integer array} containing n elements of the {@literal Fibonacci Sequence}.
   * @throws IllegalArgumentException if position (n) is less than {@literal 1}.
   * @see #fibonacciNumber(int)
   */
  public static int[] fibonacciSequence(int n) {

    Assert.argument(n, argument -> argument > 0,
      "The number of elements from the Fibonacci Sequence to calculate must be greater than equal to 0");

    int[] fibonacciNumbers = new int[n];

    for (int position = 0; position < n; position++) {
      if (position == 0) {
        fibonacciNumbers[position] = 0;
      }
      else if (position < 3) {
        fibonacciNumbers[position] = 1;
      }
      else {
        fibonacciNumbers[position] = fibonacciNumbers[position - 1] + fibonacciNumbers[position - 2];
      }
    }

    return fibonacciNumbers;
  }

  /**
   * Calculates the volume of an irregular prism.
   *
   * {@literal Volume = base * height}.
   *
   * @param base {@link Double value} declaring the base width of the prism.
   * @param height {@link Double value} declaring the height of the prism.
   * @return the volume of an irregular prism having the given base and height.
   */
  public static double irregularPrismVolume(double base, double height) {
    return base * height;
  }

  /**
   * Determines the maximum numerical value in an array of values.
   *
   * @param values array of numerical values from which to determine the maximum value.
   * @return the maximum numerical value in the given array of numerical values.
   * Returns {@link Double#NaN} if the array of values is {@literal null}.
   * @see java.lang.Math#max(double, double)
   * @see java.lang.Double#NaN
   * @see #min(double...)
   */
  @NullSafe
  public static double max(double... values) {

    double maxValue = Double.NaN;

    if (values != null) {
      for (double value : values) {
        maxValue = Double.isNaN(maxValue) ? value : Math.max(maxValue, value);
      }
    }

    return maxValue;
  }

  /**
   * Determines the minimum numerical value in an array of values.
   *
   * @param values array of numerical values from which to determine the minimum value.
   * @return the minimum numerical value in the given array of numerical values.
   * Returns {@link Double#NaN} if the array of values is {@literal null}.
   * @see java.lang.Math#min(double, double)
   * @see java.lang.Double#NaN
   * @see #max(double...)
   */
  @NullSafe
  public static double min(double... values) {

    double minValue = Double.NaN;

    if (values != null) {
      for (double value : values) {
        minValue = Double.isNaN(minValue) ? value : Math.min(minValue, value);
      }
    }

    return minValue;
  }

  /**
   * Multiplies all the numbers in an array together.
   *
   * @param numbers array of {@link Integer values} to multiply together.
   * @return a single {@link Integer value} resulting from multiply all the number in the array together.
   */
  @NullSafe
  public static int multiply(int... numbers) {

    int result = 0;

    if (numbers != null) {
      result = numbers.length > 0 ? 1 : 0;
      for (int number : numbers) {
        result *= number;
      }
    }

    return result;
  }

  /**
   * Calculates the area of a parallelogram.
   *
   * {@literal Area = base * height}.
   *
   * @param base {@link Double value} declaring the base length of the parallelogram.
   * @param height {@link Double value} declaring the height of the parallelogram.
   * @return the area of a parallelogram having the given base length and height.
   * @see #rectangleArea(double, double)
   */
  public static double parallelogramArea(double base, double height) {
    return rectangleArea(base, height);
  }

  /**
   * Calculates the volume of a pyramid.
   *
   * {@literal Volume = baseLength * baseWidth * height}.
   *
   * @param baseLength {@link Double value} declaring the base length of the pyramid.
   * @param baseWidth {@link Double value} declaring the base width of the pyramid.
   * @param height {@link Double value} declaring the height of the pyramid.
   * @return the volume of a pyramid having the given base length, base width and height.
   */
  public static double pyramidVolume(double baseLength, double baseWidth, double height) {
    return baseLength * baseWidth * height / 3.0d;
  }

  /**
   * Calculates the {@literal Pythagorean Theorem}.
   *
   * {@literal c^2 = a^2 + b^2}.
   *
   * @param a {@link Double value} for {@literal operand A}.
   * @param b {@link Double value} for {@literal operand B}.
   * @return the {@link Double value} of {@literal C} using the {@literal Pythagorean Theorem}.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#sqrt(double)
   */
  public static double pythagoreanTheorem(double a, double b) {
    return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
  }

  /**
   * Calculates the area of a rectangle.
   *
   * {@literal Area = length * height}.
   *
   * @param length {@link Double value} declaring the length of the rectangle.
   * @param height {@link Double value} declaring the height of the rectangle.
   * @return the area of a rectangle having the given length and height.
   */
  public static double rectangleArea(double length, double height) {
    return length * height;
  }

  /**
   * Calculates the surface area of a rectangular prism.
   *
   * {@literal Area = 2 * ((length * height) + (length * width) + (height * width))}.
   *
   * @param length {@link Double value} declaring the length of the rectangular prism (x-axis).
   * @param height {@link Double value} declaring the height of the rectangular prism (y-axis).
   * @param width {@link Double value} declaring the width of the rectangular prism (z-axis).
   * @return the surface area of a rectangular prism having the given length, height
   * and width (depth) of the sides.
   */
  public static double rectangularPrismSurfaceArea(double length, double height, double width) {
    return 2 * (length * height + length * width + height * width);
  }

  /**
   * Calculates the volume of a rectangular prism.
   *
   * {@literal Volume = length * width * height}.
   *
   * @param length {@link Double value} declaring the length of the rectangular prism (x-axis).
   * @param height {@link Double value} declaring the height of the rectangular prism (y-axis).
   * @param width {@link Double value} declaring the width of the rectangular prism (z-axis).
   * @return the volume of a rectangular prism having the given length, height and width.
   */
  public static double rectangularPrismVolume(double length, double height, double width) {
    return length * height * width;
  }

  /**
   * Rounds the specified {@link Double value} to the nearest tenth.
   *
   * @param value {@link Double value} to round to the nearest tenth.
   * @return the {@link Double value} rounded to the nearest tenth.
   * @see #roundToPrecision(double, int)
   */
  public static double roundToNearestTenth(double value) {
    return roundToPrecision(value, 1);
  }

  /**
   * Rounds the {@link Double value} to the nearest, given {@link Integer number of decimal places}.
   *
   * @param value {@link Double value} to round.
   * @param numberOfDecimalPlaces {@link Integer value} declaring the number of decimal places;
   * must be greater than {@literal 0}.
   * @return the given {@link Double value} rounded to nearest, given {@link Integer number of decimal places}.
   * @throws IllegalArgumentException if the {@link Integer number of decimal places}
   * is less than equal to {@literal 0}.
   * @see java.lang.Math#round(double)
   */
  public static double roundToPrecision(double value, int numberOfDecimalPlaces) {

    Assert.isTrue(numberOfDecimalPlaces > 0,
      "Number of decimal places [%d] must be greater than 0", numberOfDecimalPlaces);

    double result = value;
    double baseTenExponentialFactor = Math.pow(BASE_TEN, numberOfDecimalPlaces);

    result *= baseTenExponentialFactor;
    result = Math.round(result);
    result /= baseTenExponentialFactor;

    return result;
  }

  /**
   * Calculates the surface area of a sphere.
   *
   * {@literal A = 4πr^2 = 4 * π * radius^2}.
   *
   * @param radius {@link Double value} declaring the radius of the sphere.
   * @return the surface area of a sphere having the given radius.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#PI
   */
  public static double sphereSurfaceArea(double radius) {
    return 4.0d * Math.PI * Math.pow(radius, 2);
  }

  /**
   * Calculates the volume of a sphere.
   *
   * {@literal V = 4/3πr^3 = 4/3 * π * radius^3}.
   *
   * @param radius {@link Double value} declaring the radius of the sphere.
   * @return the volume of a sphere having the given radius.
   * @see java.lang.Math#pow(double, double)
   * @see java.lang.Math#PI
   */
  public static double sphereVolume(double radius) {
    return 4.0d * Math.PI * Math.pow(radius, 3) / 3.0d;
  }

  /**
   * Calculates the area of a square.
   *
   * {@literal A = side^2}.
   *
   * @param side {@link Double value} declaring the length of a side of the square.
   * @return the area of a square having the given length of a side.
   * @see #rectangleArea(double, double)
   */
  public static double squareArea(double side) {
    return rectangleArea(side, side);
  }

  /**
   * Calculates the sum of all {@link Integer values} in the array.
   *
   * @param numbers array of {@link Integer values} to sum.
   * @return the sum of all {@link Integer values} in the array.
   */
  @NullSafe
  public static int sum(int... numbers) {

    int sum = 0;

    if (numbers != null) {
      for (int number : numbers) {
        sum += number;
      }
    }

    return sum;
  }

  /**
   * Calculates the area of a trapezoid.
   *
   * {@literal A = (a + b) / 2 * height}.
   *
   * @param height {@link Double value} declaring the height of the trapezoid.
   * @param baseOne {@link Double value} declaring the length of one of the trapezoid's bases.
   * @param baseTwo {@link Double value} declaring the length of the other trapezoid's bases.
   * @return the area of a trapezoid having the given height and length of 2 of the bases.
   */
  public static double trapezoidArea(double height, double baseOne, double baseTwo) {
    return (baseOne + baseTwo) / 2.0d * height;
  }

  /**
   * Calculates the area of a triangle.
   *
   * {@literal A = (base * height) / 2}.
   *
   * @param base {@link Double value} declaring the length of the triangle's base.
   * @param height {@link Double value} declaring the height (highest point) of the triangle from its base.
   * @return the area of a triangle having the given base length and height.
   */
  public static double triangleArea(double base, double height) {
    return base * height / 2.0d;
  }

  /**
   * Truncates the given {@link Double value} to the given {@link Integer number of decimal places}.
   *
   * @param value {@link Double value} to truncate.
   * @param numberOfDecimalPlaces {@link Integer value} declaring the number of decimal places;
   * must be greater than {@literal 0}.
   * @return the given {@link Double value} truncated by the given {@link Integer number of decimal places}.
   * @see java.lang.Math#floor(double)
   */
  public static double truncateToPrecision(double value, int numberOfDecimalPlaces) {

    Assert.isTrue(numberOfDecimalPlaces > 0,
      "Number of decimal places [%d] must be greater than 0", numberOfDecimalPlaces);

    double result = value;
    double baseTenExponentialFactor = Math.pow(BASE_TEN, numberOfDecimalPlaces);

    result *= baseTenExponentialFactor;
    result = Math.floor(result);
    result /= baseTenExponentialFactor;

    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy