MathUtils.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.util;

  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.util.Arrays;
  25. import java.util.Properties;

  26. import org.hipparchus.CalculusFieldElement;
  27. import org.hipparchus.FieldElement;
  28. import org.hipparchus.exception.Localizable;
  29. import org.hipparchus.exception.LocalizedCoreFormats;
  30. import org.hipparchus.exception.MathIllegalArgumentException;
  31. import org.hipparchus.exception.MathRuntimeException;
  32. import org.hipparchus.exception.NullArgumentException;

  33. /**
  34.  * Miscellaneous utility functions.
  35.  *
  36.  * @see ArithmeticUtils
  37.  * @see Precision
  38.  * @see MathArrays
  39.  */
  40. public final class MathUtils {
  41.     /** \(2\pi\) */
  42.     public static final double TWO_PI = 2 * FastMath.PI;

  43.     /** \(\pi^2\) */
  44.     public static final double PI_SQUARED = FastMath.PI * FastMath.PI;

  45.     /** \(\pi/2\). */
  46.     public static final double SEMI_PI = 0.5 * FastMath.PI;

  47.     /**
  48.      * Class contains only static methods.
  49.      */
  50.     private MathUtils() {}


  51.     /**
  52.      * Returns an integer hash code representing the given double value.
  53.      *
  54.      * @param value the value to be hashed
  55.      * @return the hash code
  56.      */
  57.     public static int hash(double value) {
  58.         return Double.hashCode(value);
  59.     }

  60.     /**
  61.      * Returns {@code true} if the values are equal according to semantics of
  62.      * {@link Double#equals(Object)}.
  63.      *
  64.      * @param x Value
  65.      * @param y Value
  66.      * @return {@code Double.valueOf(x).equals(Double.valueOf(y))}
  67.      */
  68.     public static boolean equals(double x, double y) {
  69.         return Double.valueOf(x).equals(y);
  70.     }

  71.     /**
  72.      * Returns an integer hash code representing the given double array.
  73.      *
  74.      * @param value the value to be hashed (may be null)
  75.      * @return the hash code
  76.      */
  77.     public static int hash(double[] value) {
  78.         return Arrays.hashCode(value);
  79.     }

  80.     /**
  81.      * Normalize an angle in a 2π wide interval around a center value.
  82.      * <p>This method has three main uses:</p>
  83.      * <ul>
  84.      *   <li>normalize an angle between 0 and 2&pi;:<br>
  85.      *       {@code a = MathUtils.normalizeAngle(a, FastMath.PI);}</li>
  86.      *   <li>normalize an angle between -&pi; and +&pi;<br>
  87.      *       {@code a = MathUtils.normalizeAngle(a, 0.0);}</li>
  88.      *   <li>compute the angle between two defining angular positions:<br>
  89.      *       {@code angle = MathUtils.normalizeAngle(end, start) - start;}</li>
  90.      * </ul>
  91.      * <p>Note that due to numerical accuracy and since &pi; cannot be represented
  92.      * exactly, the result interval is <em>closed</em>, it cannot be half-closed
  93.      * as would be more satisfactory in a purely mathematical view.</p>
  94.      * @param a angle to normalize
  95.      * @param center center of the desired 2&pi; interval for the result
  96.      * @return a-2k&pi; with integer k and center-&pi; &lt;= a-2k&pi; &lt;= center+&pi;
  97.      */
  98.      public static double normalizeAngle(double a, double center) {
  99.          return a - TWO_PI * FastMath.floor((a + FastMath.PI - center) / TWO_PI);
  100.      }

  101.      /**
  102.       * Normalize an angle in a 2&pi; wide interval around a center value.
  103.       * <p>This method has three main uses:</p>
  104.       * <ul>
  105.       *   <li>normalize an angle between 0 and 2&pi;:<br>
  106.       *       {@code a = MathUtils.normalizeAngle(a, FastMath.PI);}</li>
  107.       *   <li>normalize an angle between -&pi; and +&pi;<br>
  108.       *       {@code a = MathUtils.normalizeAngle(a, zero);}</li>
  109.       *   <li>compute the angle between two defining angular positions:<br>
  110.       *       {@code angle = MathUtils.normalizeAngle(end, start).subtract(start);}</li>
  111.       * </ul>
  112.       * <p>Note that due to numerical accuracy and since &pi; cannot be represented
  113.       * exactly, the result interval is <em>closed</em>, it cannot be half-closed
  114.       * as would be more satisfactory in a purely mathematical view.</p>
  115.       * @param <T> the type of the field elements
  116.       * @param a angle to normalize
  117.       * @param center center of the desired 2&pi; interval for the result
  118.       * @return a-2k&pi; with integer k and center-&pi; &lt;= a-2k&pi; &lt;= center+&pi;
  119.       */
  120.       public static <T extends CalculusFieldElement<T>> T normalizeAngle(T a, T center) {
  121.           return a.subtract(FastMath.floor(a.add(FastMath.PI).subtract(center).divide(TWO_PI)).multiply(TWO_PI));
  122.       }

  123.      /** Find the maximum of two field elements.
  124.       * @param <T> the type of the field elements
  125.       * @param e1 first element
  126.       * @param e2 second element
  127.       * @return max(a1, e2)
  128.       */
  129.      public static <T extends CalculusFieldElement<T>> T max(final T e1, final T e2) {
  130.          return e1.subtract(e2).getReal() >= 0 ? e1 : e2;
  131.      }

  132.      /** Find the minimum of two field elements.
  133.       * @param <T> the type of the field elements
  134.       * @param e1 first element
  135.       * @param e2 second element
  136.       * @return min(a1, e2)
  137.       */
  138.      public static <T extends CalculusFieldElement<T>> T min(final T e1, final T e2) {
  139.          return e1.subtract(e2).getReal() >= 0 ? e2 : e1;
  140.      }

  141.     /**
  142.      * <p>Reduce {@code |a - offset|} to the primary interval
  143.      * {@code [0, |period|)}.</p>
  144.      *
  145.      * <p>Specifically, the value returned is <br>
  146.      * {@code a - |period| * floor((a - offset) / |period|) - offset}.</p>
  147.      *
  148.      * <p>If any of the parameters are {@code NaN} or infinite, the result is
  149.      * {@code NaN}.</p>
  150.      *
  151.      * @param a Value to reduce.
  152.      * @param period Period.
  153.      * @param offset Value that will be mapped to {@code 0}.
  154.      * @return the value, within the interval {@code [0 |period|)},
  155.      * that corresponds to {@code a}.
  156.      */
  157.     public static double reduce(double a,
  158.                                 double period,
  159.                                 double offset) {
  160.         final double p = FastMath.abs(period);
  161.         return a - p * FastMath.floor((a - offset) / p) - offset;
  162.     }

  163.     /**
  164.      * Returns the first argument with the sign of the second argument.
  165.      *
  166.      * @param magnitude Magnitude of the returned value.
  167.      * @param sign Sign of the returned value.
  168.      * @return a value with magnitude equal to {@code magnitude} and with the
  169.      * same sign as the {@code sign} argument.
  170.      * @throws MathRuntimeException if {@code magnitude == Byte.MIN_VALUE}
  171.      * and {@code sign >= 0}.
  172.      */
  173.     public static byte copySign(byte magnitude, byte sign)
  174.         throws MathRuntimeException {
  175.         if ((magnitude >= 0 && sign >= 0) ||
  176.             (magnitude < 0 && sign < 0)) { // Sign is OK.
  177.             return magnitude;
  178.         } else if (sign >= 0 &&
  179.                    magnitude == Byte.MIN_VALUE) {
  180.             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW);
  181.         } else {
  182.             return (byte) -magnitude; // Flip sign.
  183.         }
  184.     }

  185.     /**
  186.      * Returns the first argument with the sign of the second argument.
  187.      *
  188.      * @param magnitude Magnitude of the returned value.
  189.      * @param sign Sign of the returned value.
  190.      * @return a value with magnitude equal to {@code magnitude} and with the
  191.      * same sign as the {@code sign} argument.
  192.      * @throws MathRuntimeException if {@code magnitude == Short.MIN_VALUE}
  193.      * and {@code sign >= 0}.
  194.      */
  195.     public static short copySign(short magnitude, short sign)
  196.             throws MathRuntimeException {
  197.         if ((magnitude >= 0 && sign >= 0) ||
  198.             (magnitude < 0 && sign < 0)) { // Sign is OK.
  199.             return magnitude;
  200.         } else if (sign >= 0 &&
  201.                    magnitude == Short.MIN_VALUE) {
  202.             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW);
  203.         } else {
  204.             return (short) -magnitude; // Flip sign.
  205.         }
  206.     }

  207.     /**
  208.      * Returns the first argument with the sign of the second argument.
  209.      *
  210.      * @param magnitude Magnitude of the returned value.
  211.      * @param sign Sign of the returned value.
  212.      * @return a value with magnitude equal to {@code magnitude} and with the
  213.      * same sign as the {@code sign} argument.
  214.      * @throws MathRuntimeException if {@code magnitude == Integer.MIN_VALUE}
  215.      * and {@code sign >= 0}.
  216.      */
  217.     public static int copySign(int magnitude, int sign)
  218.             throws MathRuntimeException {
  219.         if ((magnitude >= 0 && sign >= 0) ||
  220.             (magnitude < 0 && sign < 0)) { // Sign is OK.
  221.             return magnitude;
  222.         } else if (sign >= 0 &&
  223.                    magnitude == Integer.MIN_VALUE) {
  224.             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW);
  225.         } else {
  226.             return -magnitude; // Flip sign.
  227.         }
  228.     }

  229.     /**
  230.      * Returns the first argument with the sign of the second argument.
  231.      *
  232.      * @param magnitude Magnitude of the returned value.
  233.      * @param sign Sign of the returned value.
  234.      * @return a value with magnitude equal to {@code magnitude} and with the
  235.      * same sign as the {@code sign} argument.
  236.      * @throws MathRuntimeException if {@code magnitude == Long.MIN_VALUE}
  237.      * and {@code sign >= 0}.
  238.      */
  239.     public static long copySign(long magnitude, long sign)
  240.         throws MathRuntimeException {
  241.         if ((magnitude >= 0 && sign >= 0) ||
  242.             (magnitude < 0 && sign < 0)) { // Sign is OK.
  243.             return magnitude;
  244.         } else if (sign >= 0 &&
  245.                    magnitude == Long.MIN_VALUE) {
  246.             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW);
  247.         } else {
  248.             return -magnitude; // Flip sign.
  249.         }
  250.     }
  251.     /**
  252.      * Check that the argument is a real number.
  253.      *
  254.      * @param x Argument.
  255.      * @throws MathIllegalArgumentException if {@code x} is not a
  256.      * finite real number.
  257.      */
  258.     public static void checkFinite(final double x)
  259.         throws MathIllegalArgumentException {
  260.         if (Double.isInfinite(x) || Double.isNaN(x)) {
  261.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NOT_FINITE_NUMBER, x);
  262.         }
  263.     }

  264.     /**
  265.      * Check that all the elements are real numbers.
  266.      *
  267.      * @param val Arguments.
  268.      * @throws MathIllegalArgumentException if any values of the array is not a
  269.      * finite real number.
  270.      */
  271.     public static void checkFinite(final double[] val)
  272.         throws MathIllegalArgumentException {
  273.         for (final double x : val) {
  274.             if (Double.isInfinite(x) || Double.isNaN(x)) {
  275.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.NOT_FINITE_NUMBER, x);
  276.             }
  277.         }
  278.     }

  279.     /**
  280.      * Checks that an object is not null.
  281.      *
  282.      * @param o Object to be checked.
  283.      * @param pattern Message pattern.
  284.      * @param args Arguments to replace the placeholders in {@code pattern}.
  285.      * @throws NullArgumentException if {@code o} is {@code null}.
  286.      */
  287.     public static void checkNotNull(Object o,
  288.                                     Localizable pattern,
  289.                                     Object ... args)
  290.         throws NullArgumentException {
  291.         if (o == null) {
  292.             throw new NullArgumentException(pattern, args);
  293.         }
  294.     }

  295.     /**
  296.      * Checks that an object is not null.
  297.      *
  298.      * @param o Object to be checked.
  299.      * @throws NullArgumentException if {@code o} is {@code null}.
  300.      */
  301.     public static void checkNotNull(Object o)
  302.         throws NullArgumentException {
  303.         if (o == null) {
  304.             throw new NullArgumentException(LocalizedCoreFormats.NULL_NOT_ALLOWED);
  305.         }
  306.     }

  307.     /**
  308.      * Checks that the given value is strictly within the range [lo, hi].
  309.      *
  310.      * @param value value to be checked.
  311.      * @param lo the lower bound (inclusive).
  312.      * @param hi the upper bound (inclusive).
  313.      * @throws MathIllegalArgumentException if {@code value} is strictly outside [lo, hi].
  314.      */
  315.     public static void checkRangeInclusive(long value, long lo, long hi) {
  316.         if (value < lo || value > hi) {
  317.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  318.                                                    value, lo, hi);
  319.         }
  320.     }

  321.     /**
  322.      * Checks that the given value is strictly within the range [lo, hi].
  323.      *
  324.      * @param value value to be checked.
  325.      * @param lo the lower bound (inclusive).
  326.      * @param hi the upper bound (inclusive).
  327.      * @throws MathIllegalArgumentException if {@code value} is strictly outside [lo, hi].
  328.      */
  329.     public static void checkRangeInclusive(double value, double lo, double hi) {
  330.         if (value < lo || value > hi) {
  331.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  332.                                                    value, lo, hi);
  333.         }
  334.     }

  335.     /**
  336.      * Checks that the given dimensions match.
  337.      *
  338.      * @param dimension the first dimension.
  339.      * @param otherDimension the second dimension.
  340.      * @throws MathIllegalArgumentException if length != otherLength.
  341.      */
  342.     public static void checkDimension(int dimension, int otherDimension) {
  343.         if (dimension != otherDimension) {
  344.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  345.                                                    dimension, otherDimension);
  346.         }
  347.     }

  348.     /**
  349.      * Get Hipparchus version.
  350.      * <p>
  351.      * The version is automatically retrieved from a properties file generated
  352.      * at maven compilation time. When using an IDE not configured to use
  353.      * maven, then a default value {@code "unknown"} will be returned.
  354.      * </p>
  355.      * @return hipparchus version
  356.      * @since 4.0
  357.      */
  358.     public static String getHipparchusVersion() {
  359.         String version = "unknown";
  360.         final Properties properties = new Properties();
  361.         try (InputStream stream = MathUtils.class.getResourceAsStream("/assets/org/hipparchus/hipparchus.properties")) {
  362.             if (stream != null) {
  363.                 properties.load(stream);
  364.                 version = properties.getProperty("hipparchus.version", version);
  365.             }
  366.         } catch (IOException ioe) { // NOPMD
  367.             // ignored
  368.         }
  369.         return version;
  370.     }

  371.     /**
  372.      * Sums {@code a} and {@code b} using Møller's 2Sum algorithm.
  373.      * <p>
  374.      * References:
  375.      * <ul>
  376.      * <li>Møller, Ole. "Quasi double-precision in floating point addition." BIT
  377.      * 5, 37–50 (1965).</li>
  378.      * <li>Shewchuk, Richard J. "Adaptive Precision Floating-Point Arithmetic
  379.      * and Fast Robust Geometric Predicates." Discrete &amp; Computational Geometry
  380.      * 18, 305–363 (1997).</li>
  381.      * <li><a href=
  382.      * "https://en.wikipedia.org/wiki/2Sum">https://en.wikipedia.org/wiki/2Sum</a></li>
  383.      * </ul>
  384.      * @param a first summand
  385.      * @param b second summand
  386.      * @return sum and residual error in the sum
  387.      */
  388.     public static SumAndResidual twoSum(final double a, final double b) {
  389.         final double s = a + b;
  390.         final double aPrime = s - b;
  391.         final double bPrime = s - aPrime;
  392.         final double deltaA = a - aPrime;
  393.         final double deltaB = b - bPrime;
  394.         final double t = deltaA + deltaB;
  395.         return new SumAndResidual(s, t);
  396.     }

  397.     /**
  398.      * Sums {@code a} and {@code b} using Møller's 2Sum algorithm.
  399.      * <p>
  400.      * References:
  401.      * <ul>
  402.      * <li>Møller, Ole. "Quasi double-precision in floating point addition." BIT
  403.      * 5, 37–50 (1965).</li>
  404.      * <li>Shewchuk, Richard J. "Adaptive Precision Floating-Point Arithmetic
  405.      * and Fast Robust Geometric Predicates." Discrete &amp; Computational Geometry
  406.      * 18, 305–363 (1997).</li>
  407.      * <li><a href=
  408.      * "https://en.wikipedia.org/wiki/2Sum">https://en.wikipedia.org/wiki/2Sum</a></li>
  409.      * </ul>
  410.      * @param <T> field element type
  411.      * @param a first summand
  412.      * @param b second summand
  413.      * @return sum and residual error in the sum
  414.      */
  415.     public static <T extends FieldElement<T>> FieldSumAndResidual<T> twoSum(final T a, final T b) {
  416.         final T s = a.add(b);
  417.         final T aPrime = s.subtract(b);
  418.         final T bPrime = s.subtract(aPrime);
  419.         final T deltaA = a.subtract(aPrime);
  420.         final T deltaB = b.subtract(bPrime);
  421.         final T t = deltaA.add(deltaB);
  422.         return new FieldSumAndResidual<>(s, t);
  423.     }

  424.     /**
  425.      * Result class for {@link MathUtils#twoSum(double, double)} containing the
  426.      * sum and the residual error in the sum.
  427.      */
  428.     public static final class SumAndResidual {

  429.         /** Sum. */
  430.         private final double sum;
  431.         /** Residual error in the sum. */
  432.         private final double residual;

  433.         /**
  434.          * Constructs a {@link SumAndResidual} instance.
  435.          * @param sum sum
  436.          * @param residual residual error in the sum
  437.          */
  438.         private SumAndResidual(final double sum, final double residual) {
  439.             this.sum = sum;
  440.             this.residual = residual;
  441.         }

  442.         /**
  443.          * Returns the sum.
  444.          * @return sum
  445.          */
  446.         public double getSum() {
  447.             return sum;
  448.         }

  449.         /**
  450.          * Returns the residual error in the sum.
  451.          * @return residual error in the sum
  452.          */
  453.         public double getResidual() {
  454.             return residual;
  455.         }

  456.     }

  457.     /**
  458.      * Result class for
  459.      * {@link MathUtils#twoSum(FieldElement, FieldElement)} containing
  460.      * the sum and the residual error in the sum.
  461.      * @param <T> field element type
  462.      */
  463.     public static final class FieldSumAndResidual<T extends FieldElement<T>> {

  464.         /** Sum. */
  465.         private final T sum;
  466.         /** Residual error in the sum. */
  467.         private final T residual;

  468.         /**
  469.          * Constructs a {@link FieldSumAndResidual} instance.
  470.          * @param sum sum
  471.          * @param residual residual error in the sum
  472.          */
  473.         private FieldSumAndResidual(final T sum, final T residual) {
  474.             this.sum = sum;
  475.             this.residual = residual;
  476.         }

  477.         /**
  478.          * Returns the sum.
  479.          * @return sum
  480.          */
  481.         public T getSum() {
  482.             return sum;
  483.         }

  484.         /**
  485.          * Returns the residual error in the sum.
  486.          * @return residual error in the sum
  487.          */
  488.         public T getResidual() {
  489.             return residual;
  490.         }

  491.     }

  492. }