Description
Returns the least common multiple of the given absolute values.
License
Apache License
Parameter
Parameter | Description |
---|
args | non-negative numbers |
Exception
Parameter | Description |
---|
ArithmeticException | if the result cannot be represented as a non-negative int value. |
Return
the least common multiple, never negative.
Declaration
public static int lcmPositive(int... args)
Method Source Code
//package com.java2s;
/*******************************************************************************
* Copyright 2014 See AUTHORS file.//from w ww . j a v a 2 s . co m
*
* 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.
******************************************************************************/
public class Main {
/** Returns the least common multiple of the absolute value of two numbers, using the formula
* {@code lcm(a, b) = (a / gcd(a, b)) * b}.
* <p>
* Special cases:
* <ul>
* <li>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 {@code int} value.</li>
* <li>The result of {@code lcm(0, x)} and {@code lcm(x, 0)} is {@code 0} for any {@code x}.
* </ul>
*
* @param a a non-negative number.
* @param b a non-negative number.
* @return the least common multiple, never negative.
* @throws ArithmeticException if the result cannot be represented as a non-negative {@code int} value. */
public static int lcmPositive(int a, int b) throws ArithmeticException {
if (a == 0 || b == 0)
return 0;
int lcm = Math.abs(mulAndCheck(a / gcdPositive(a, b), b));
if (lcm == Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: lcm(" + a + ", " + b + ") > 2^31");
}
return lcm;
}
/** Returns the least common multiple of the given absolute values. This implementation uses {@link #lcmPositive(int, int)} and
* has the same special cases.
*
* @param args non-negative numbers
* @return the least common multiple, never negative.
* @throws ArithmeticException if the result cannot be represented as a non-negative {@code int} value. */
public static int lcmPositive(int... args) {
if (args == null || args.length < 2)
throw new IllegalArgumentException("lcmPositive requires at least two arguments");
int result = args[0];
int n = args.length;
for (int i = 1; i < n; i++) {
result = lcmPositive(result, args[i]);
}
return result;
}
/** Multiply two integers, checking for overflow.
*
* @param x first factor
* @param y second factor
* @return the product {@code x * y}.
* @throws ArithmeticException if the result can not be represented as an {@code int}. */
public static int mulAndCheck(int x, int y) throws ArithmeticException {
long m = ((long) x) * ((long) y);
if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
throw new ArithmeticException();
}
return (int) m;
}
/** Returns the greatest common divisor of two <em>positive</em> numbers (this precondition is <em>not</em> 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).
* <p>
* Special cases:
* <ul>
* <li>The result of {@code gcd(x, x)}, {@code gcd(0, x)} and {@code gcd(x, 0)} is the value of {@code x}.</li>
* <li>The invocation {@code gcd(0, 0)} is the only one which returns {@code 0}.</li>
* </ul>
*
* @param a a non negative number.
* @param b a non negative number.
* @return the greatest common divisor. */
public static int gcdPositive(int a, int b) {
if (a == 0)
return b;
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 = aTwos <= bTwos ? aTwos : bTwos; // 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 = a <= b ? a : b; // min(a, b);
a = delta < 0 ? -delta : delta; // 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;
}
/** Returns the greatest common divisor of the given absolute values. This implementation uses {@link #gcdPositive(int, int)}
* and has the same special cases.
*
* @param args non-negative numbers
* @return the greatest common divisor. */
public static int gcdPositive(int... args) {
if (args == null || args.length < 2)
throw new IllegalArgumentException("gcdPositive requires at least two arguments");
int result = args[0];
int n = args.length;
for (int i = 1; i < n; i++) {
result = gcdPositive(result, args[i]);
}
return result;
}
}
Related
- lcm(long a, long b)
- lcm(long u, long v)
- lcm(long x, long y)
- lcm(long[] a)
- LCM1(int A, int B)