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

org.hipparchus.util.ArithmeticUtils Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.hipparchus.util;

import java.math.BigInteger;

import org.hipparchus.exception.Localizable;
import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.exception.MathRuntimeException;
import org.hipparchus.exception.MathIllegalArgumentException;

/**
 * Some useful, arithmetics related, additions to the built-in functions in
 * {@link Math}.
 */
public final class ArithmeticUtils {

    /** Private constructor. */
    private ArithmeticUtils() {
        super();
    }

    /**
     * Add two integers, checking for overflow.
     *
     * @param x an addend
     * @param y an addend
     * @return the sum {@code x+y}
     * @throws MathRuntimeException if the result can not be represented
     * as an {@code int}.
     */
    public static int addAndCheck(int x, int y)
            throws MathRuntimeException {
        long s = (long)x + (long)y;
        if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
            throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_ADDITION, x, y);
        }
        return (int)s;
    }

    /**
     * Add two long integers, checking for overflow.
     *
     * @param a an addend
     * @param b an addend
     * @return the sum {@code a+b}
     * @throws MathRuntimeException if the result can not be represented as an long
     */
    public static long addAndCheck(long a, long b) throws MathRuntimeException {
        return addAndCheck(a, b, LocalizedCoreFormats.OVERFLOW_IN_ADDITION);
    }

    /**
     * Computes the greatest common divisor of the absolute value of two
     * numbers, using a modified version of the "binary gcd" method.
     * See Knuth 4.5.2 algorithm B.
     * The algorithm is due to Josef Stein (1961).
     * 
* Special cases: *
    *
  • The invocations * {@code gcd(Integer.MIN_VALUE, Integer.MIN_VALUE)}, * {@code gcd(Integer.MIN_VALUE, 0)} and * {@code gcd(0, Integer.MIN_VALUE)} throw an * {@code ArithmeticException}, because the result would be 2^31, which * is too large for an int value.
  • *
  • The result of {@code gcd(x, x)}, {@code gcd(0, x)} and * {@code gcd(x, 0)} is the absolute value of {@code x}, except * for the special cases above.
  • *
  • The invocation {@code gcd(0, 0)} is the only one which returns * {@code 0}.
  • *
* * @param p Number. * @param q Number. * @return the greatest common divisor (never negative). * @throws MathRuntimeException if the result cannot be represented as * a non-negative {@code int} value. */ public static int gcd(int p, int q) throws MathRuntimeException { int a = p; int b = q; if (a == 0 || b == 0) { if (a == Integer.MIN_VALUE || b == Integer.MIN_VALUE) { throw new MathRuntimeException(LocalizedCoreFormats.GCD_OVERFLOW_32_BITS, p, q); } return FastMath.abs(a + b); } long al = a; long bl = b; boolean useLong = false; if (a < 0) { if(Integer.MIN_VALUE == a) { useLong = true; } else { a = -a; } al = -al; } if (b < 0) { if (Integer.MIN_VALUE == b) { useLong = true; } else { b = -b; } bl = -bl; } if (useLong) { if(al == bl) { throw new MathRuntimeException(LocalizedCoreFormats.GCD_OVERFLOW_32_BITS, p, q); } long blbu = bl; bl = al; al = blbu % al; if (al == 0) { if (bl > Integer.MAX_VALUE) { throw new MathRuntimeException(LocalizedCoreFormats.GCD_OVERFLOW_32_BITS, p, q); } return (int) bl; } blbu = bl; // Now "al" and "bl" fit in an "int". b = (int) al; a = (int) (blbu % al); } return gcdPositive(a, b); } /** * Computes the greatest common divisor of two positive numbers * (this precondition is not checked and the result is undefined * if not fulfilled) using the "binary gcd" method which avoids division * and modulo operations. * See Knuth 4.5.2 algorithm B. * The algorithm is due to Josef Stein (1961). *

* Special cases: *

    *
  • The result of {@code gcd(x, x)}, {@code gcd(0, x)} and * {@code gcd(x, 0)} is the value of {@code x}.
  • *
  • The invocation {@code gcd(0, 0)} is the only one which returns * {@code 0}.
  • *
* * @param a Positive number. * @param b Positive number. * @return the greatest common divisor. */ private static int gcdPositive(int a, int b) { if (a == 0) { return b; } else if (b == 0) { return a; } // Make "a" and "b" odd, keeping track of common power of 2. final int aTwos = Integer.numberOfTrailingZeros(a); a >>= aTwos; final int bTwos = Integer.numberOfTrailingZeros(b); b >>= bTwos; final int shift = FastMath.min(aTwos, bTwos); // "a" and "b" are positive. // If a > b then "gdc(a, b)" is equal to "gcd(a - b, b)". // If a < b then "gcd(a, b)" is equal to "gcd(b - a, a)". // Hence, in the successive iterations: // "a" becomes the absolute difference of the current values, // "b" becomes the minimum of the current values. while (a != b) { final int delta = a - b; b = Math.min(a, b); a = Math.abs(delta); // Remove any power of 2 in "a" ("b" is guaranteed to be odd). a >>= Integer.numberOfTrailingZeros(a); } // Recover the common power of 2. return a << shift; } /** * Gets the greatest common divisor of the absolute value of two numbers, * using the "binary gcd" method which avoids division and modulo * operations. See Knuth 4.5.2 algorithm B. This algorithm is due to Josef * Stein (1961). *

* Special cases: *

    *
  • The invocations * {@code gcd(Long.MIN_VALUE, Long.MIN_VALUE)}, * {@code gcd(Long.MIN_VALUE, 0L)} and * {@code gcd(0L, Long.MIN_VALUE)} throw an * {@code ArithmeticException}, because the result would be 2^63, which * is too large for a long value.
  • *
  • The result of {@code gcd(x, x)}, {@code gcd(0L, x)} and * {@code gcd(x, 0L)} is the absolute value of {@code x}, except * for the special cases above. *
  • The invocation {@code gcd(0L, 0L)} is the only one which returns * {@code 0L}.
  • *
* * @param p Number. * @param q Number. * @return the greatest common divisor, never negative. * @throws MathRuntimeException if the result cannot be represented as * a non-negative {@code long} value. */ public static long gcd(final long p, final long q) throws MathRuntimeException { long u = p; long v = q; if ((u == 0) || (v == 0)) { if ((u == Long.MIN_VALUE) || (v == Long.MIN_VALUE)){ throw new MathRuntimeException(LocalizedCoreFormats.GCD_OVERFLOW_64_BITS, p, q); } return FastMath.abs(u) + FastMath.abs(v); } // keep u and v negative, as negative integers range down to // -2^63, while positive numbers can only be as large as 2^63-1 // (i.e. we can't necessarily negate a negative number without // overflow) /* assert u!=0 && v!=0; */ if (u > 0) { u = -u; } // make u negative if (v > 0) { v = -v; } // make v negative // B1. [Find power of 2] int k = 0; while ((u & 1) == 0 && (v & 1) == 0 && k < 63) { // while u and v are // both even... u /= 2; v /= 2; k++; // cast out twos. } if (k == 63) { throw new MathRuntimeException(LocalizedCoreFormats.GCD_OVERFLOW_64_BITS, p, q); } // B2. Initialize: u and v have been divided by 2^k and at least // one is odd. long t = ((u & 1) == 1) ? v : -(u / 2)/* B3 */; // t negative: u was odd, v may be even (t replaces v) // t positive: u was even, v is odd (t replaces u) do { /* assert u<0 && v<0; */ // B4/B3: cast out twos from t. while ((t & 1) == 0) { // while t is even.. t /= 2; // cast out twos } // B5 [reset max(u,v)] if (t > 0) { u = -t; } else { v = t; } // B6/B3. at this point both u and v should be odd. t = (v - u) / 2; // |u| larger: t positive (replace u) // |v| larger: t negative (replace v) } while (t != 0); return -u * (1L << k); // gcd is u*2^k } /** * Returns the least common multiple of the absolute value of two numbers, * using the formula {@code lcm(a,b) = (a / gcd(a,b)) * b}. *

* Special cases: *

    *
  • The invocations {@code lcm(Integer.MIN_VALUE, n)} and * {@code lcm(n, Integer.MIN_VALUE)}, where {@code abs(n)} is a * power of 2, throw an {@code ArithmeticException}, because the result * would be 2^31, which is too large for an int value.
  • *
  • The result of {@code lcm(0, x)} and {@code lcm(x, 0)} is * {@code 0} for any {@code x}. *
* * @param a Number. * @param b Number. * @return the least common multiple, never negative. * @throws MathRuntimeException if the result cannot be represented as * a non-negative {@code int} value. */ public static int lcm(int a, int b) throws MathRuntimeException { if (a == 0 || b == 0){ return 0; } int lcm = FastMath.abs(ArithmeticUtils.mulAndCheck(a / gcd(a, b), b)); if (lcm == Integer.MIN_VALUE) { throw new MathRuntimeException(LocalizedCoreFormats.LCM_OVERFLOW_32_BITS, a, b); } return lcm; } /** * Returns the least common multiple of the absolute value of two numbers, * using the formula {@code lcm(a,b) = (a / gcd(a,b)) * b}. *

* Special cases: *

    *
  • The invocations {@code lcm(Long.MIN_VALUE, n)} and * {@code lcm(n, Long.MIN_VALUE)}, where {@code abs(n)} is a * power of 2, throw an {@code ArithmeticException}, because the result * would be 2^63, which is too large for an int value.
  • *
  • The result of {@code lcm(0L, x)} and {@code lcm(x, 0L)} is * {@code 0L} for any {@code x}. *
* * @param a Number. * @param b Number. * @return the least common multiple, never negative. * @throws MathRuntimeException if the result cannot be represented * as a non-negative {@code long} value. */ public static long lcm(long a, long b) throws MathRuntimeException { if (a == 0 || b == 0){ return 0; } long lcm = FastMath.abs(ArithmeticUtils.mulAndCheck(a / gcd(a, b), b)); if (lcm == Long.MIN_VALUE){ throw new MathRuntimeException(LocalizedCoreFormats.LCM_OVERFLOW_64_BITS, a, b); } return lcm; } /** * Multiply two integers, checking for overflow. * * @param x Factor. * @param y Factor. * @return the product {@code x * y}. * @throws MathRuntimeException if the result can not be * represented as an {@code int}. */ public static int mulAndCheck(int x, int y) throws MathRuntimeException { long m = ((long)x) * ((long)y); if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) { throw new MathRuntimeException(LocalizedCoreFormats.ARITHMETIC_EXCEPTION); } return (int)m; } /** * Multiply two long integers, checking for overflow. * * @param a Factor. * @param b Factor. * @return the product {@code a * b}. * @throws MathRuntimeException if the result can not be represented * as a {@code long}. */ public static long mulAndCheck(long a, long b) throws MathRuntimeException { long ret; if (a > b) { // use symmetry to reduce boundary cases ret = mulAndCheck(b, a); } else { if (a < 0) { if (b < 0) { // check for positive overflow with negative a, negative b if (a >= Long.MAX_VALUE / b) { ret = a * b; } else { throw new MathRuntimeException(LocalizedCoreFormats.ARITHMETIC_EXCEPTION); } } else if (b > 0) { // check for negative overflow with negative a, positive b if (Long.MIN_VALUE / b <= a) { ret = a * b; } else { throw new MathRuntimeException(LocalizedCoreFormats.ARITHMETIC_EXCEPTION); } } else { // assert b == 0 ret = 0; } } else if (a > 0) { // assert a > 0 // assert b > 0 // check for positive overflow with positive a, positive b if (a <= Long.MAX_VALUE / b) { ret = a * b; } else { throw new MathRuntimeException(LocalizedCoreFormats.ARITHMETIC_EXCEPTION); } } else { // assert a == 0 ret = 0; } } return ret; } /** * Subtract two integers, checking for overflow. * * @param x Minuend. * @param y Subtrahend. * @return the difference {@code x - y}. * @throws MathRuntimeException if the result can not be represented * as an {@code int}. */ public static int subAndCheck(int x, int y) throws MathRuntimeException { long s = (long)x - (long)y; if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_SUBTRACTION, x, y); } return (int)s; } /** * Subtract two long integers, checking for overflow. * * @param a Value. * @param b Value. * @return the difference {@code a - b}. * @throws MathRuntimeException if the result can not be represented as a * {@code long}. */ public static long subAndCheck(long a, long b) throws MathRuntimeException { long ret; if (b == Long.MIN_VALUE) { if (a < 0) { ret = a - b; } else { throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_ADDITION, a, -b); } } else { // use additive inverse ret = addAndCheck(a, -b, LocalizedCoreFormats.OVERFLOW_IN_ADDITION); } return ret; } /** * Raise an int to an int power. * * @param k Number to raise. * @param e Exponent (must be positive or zero). * @return \( k^e \) * @throws MathIllegalArgumentException if {@code e < 0}. * @throws MathRuntimeException if the result would overflow. */ public static int pow(final int k, final int e) throws MathIllegalArgumentException, MathRuntimeException { if (e < 0) { throw new MathIllegalArgumentException(LocalizedCoreFormats.EXPONENT, e); } int exp = e; int result = 1; int k2p = k; while (true) { if ((exp & 0x1) != 0) { result = mulAndCheck(result, k2p); } exp >>= 1; if (exp == 0) { break; } k2p = mulAndCheck(k2p, k2p); } return result; } /** * Raise a long to an int power. * * @param k Number to raise. * @param e Exponent (must be positive or zero). * @return \( k^e \) * @throws MathIllegalArgumentException if {@code e < 0}. * @throws MathRuntimeException if the result would overflow. */ public static long pow(final long k, final int e) throws MathIllegalArgumentException, MathRuntimeException { if (e < 0) { throw new MathIllegalArgumentException(LocalizedCoreFormats.EXPONENT, e); } int exp = e; long result = 1; long k2p = k; while (true) { if ((exp & 0x1) != 0) { result = mulAndCheck(result, k2p); } exp >>= 1; if (exp == 0) { break; } k2p = mulAndCheck(k2p, k2p); } return result; } /** * Raise a BigInteger to an int power. * * @param k Number to raise. * @param e Exponent (must be positive or zero). * @return ke * @throws MathIllegalArgumentException if {@code e < 0}. */ public static BigInteger pow(final BigInteger k, int e) throws MathIllegalArgumentException { if (e < 0) { throw new MathIllegalArgumentException(LocalizedCoreFormats.EXPONENT, e); } return k.pow(e); } /** * Raise a BigInteger to a long power. * * @param k Number to raise. * @param e Exponent (must be positive or zero). * @return ke * @throws MathIllegalArgumentException if {@code e < 0}. */ public static BigInteger pow(final BigInteger k, long e) throws MathIllegalArgumentException { if (e < 0) { throw new MathIllegalArgumentException(LocalizedCoreFormats.EXPONENT, e); } BigInteger result = BigInteger.ONE; BigInteger k2p = k; while (e != 0) { if ((e & 0x1) != 0) { result = result.multiply(k2p); } k2p = k2p.multiply(k2p); e >>= 1; } return result; } /** * Raise a BigInteger to a BigInteger power. * * @param k Number to raise. * @param e Exponent (must be positive or zero). * @return ke * @throws MathIllegalArgumentException if {@code e < 0}. */ public static BigInteger pow(final BigInteger k, BigInteger e) throws MathIllegalArgumentException { if (e.compareTo(BigInteger.ZERO) < 0) { throw new MathIllegalArgumentException(LocalizedCoreFormats.EXPONENT, e); } BigInteger result = BigInteger.ONE; BigInteger k2p = k; while (!BigInteger.ZERO.equals(e)) { if (e.testBit(0)) { result = result.multiply(k2p); } k2p = k2p.multiply(k2p); e = e.shiftRight(1); } return result; } /** * Add two long integers, checking for overflow. * * @param a Addend. * @param b Addend. * @param pattern Pattern to use for any thrown exception. * @return the sum {@code a + b}. * @throws MathRuntimeException if the result cannot be represented * as a {@code long}. */ private static long addAndCheck(long a, long b, Localizable pattern) throws MathRuntimeException { final long result = a + b; if (!((a ^ b) < 0 || (a ^ result) >= 0)) { throw new MathRuntimeException(pattern, a, b); } return result; } /** * Returns true if the argument is a power of two. * * @param n the number to test * @return true if the argument is a power of two */ public static boolean isPowerOfTwo(long n) { return (n > 0) && ((n & (n - 1)) == 0); } /** * Returns the unsigned remainder from dividing the first argument * by the second where each argument and the result is interpreted * as an unsigned value. *

* This method does not use the {@code long} datatype. * * @param dividend the value to be divided * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument. */ public static int remainderUnsigned(int dividend, int divisor) { if (divisor >= 0) { if (dividend >= 0) { return dividend % divisor; } // The implementation is a Java port of algorithm described in the book // "Hacker's Delight" (section "Unsigned short division from signed division"). int q = ((dividend >>> 1) / divisor) << 1; dividend -= q * divisor; if (dividend < 0 || dividend >= divisor) { dividend -= divisor; } return dividend; } return dividend >= 0 || dividend < divisor ? dividend : dividend - divisor; } /** * Returns the unsigned remainder from dividing the first argument * by the second where each argument and the result is interpreted * as an unsigned value. *

* This method does not use the {@code BigInteger} datatype. * * @param dividend the value to be divided * @param divisor the value doing the dividing * @return the unsigned remainder of the first argument divided by * the second argument. */ public static long remainderUnsigned(long dividend, long divisor) { if (divisor >= 0L) { if (dividend >= 0L) { return dividend % divisor; } // The implementation is a Java port of algorithm described in the book // "Hacker's Delight" (section "Unsigned short division from signed division"). long q = ((dividend >>> 1) / divisor) << 1; dividend -= q * divisor; if (dividend < 0L || dividend >= divisor) { dividend -= divisor; } return dividend; } return dividend >= 0L || dividend < divisor ? dividend : dividend - divisor; } /** * Returns the unsigned quotient of dividing the first argument by * the second where each argument and the result is interpreted as * an unsigned value. *

* Note that in two's complement arithmetic, the three other * basic arithmetic operations of add, subtract, and multiply are * bit-wise identical if the two operands are regarded as both * being signed or both being unsigned. Therefore separate {@code * addUnsigned}, etc. methods are not provided. *

* This method does not use the {@code long} datatype. * * @param dividend the value to be divided * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument */ public static int divideUnsigned(int dividend, int divisor) { if (divisor >= 0) { if (dividend >= 0) { return dividend / divisor; } // The implementation is a Java port of algorithm described in the book // "Hacker's Delight" (section "Unsigned short division from signed division"). int q = ((dividend >>> 1) / divisor) << 1; dividend -= q * divisor; if (dividend < 0L || dividend >= divisor) { q++; } return q; } return dividend >= 0 || dividend < divisor ? 0 : 1; } /** * Returns the unsigned quotient of dividing the first argument by * the second where each argument and the result is interpreted as * an unsigned value. *

* Note that in two's complement arithmetic, the three other * basic arithmetic operations of add, subtract, and multiply are * bit-wise identical if the two operands are regarded as both * being signed or both being unsigned. Therefore separate {@code * addUnsigned}, etc. methods are not provided. *

* This method does not use the {@code BigInteger} datatype. * * @param dividend the value to be divided * @param divisor the value doing the dividing * @return the unsigned quotient of the first argument divided by * the second argument. */ public static long divideUnsigned(long dividend, long divisor) { if (divisor >= 0L) { if (dividend >= 0L) { return dividend / divisor; } // The implementation is a Java port of algorithm described in the book // "Hacker's Delight" (section "Unsigned short division from signed division"). long q = ((dividend >>> 1) / divisor) << 1; dividend -= q * divisor; if (dividend < 0L || dividend >= divisor) { q++; } return q; } return dividend >= 0L || dividend < divisor ? 0L : 1L; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy