📌  相关文章
📜  Java番石榴 | IntMath 类的 gcd(int a, int b) 方法(1)

📅  最后修改于: 2023-12-03 15:32:04.133000             🧑  作者: Mango

Java番石榴 | IntMath 类的 gcd(int a, int b) 方法

Java番石榴(Guava)是一个Google开发的Java类库,它提供了许多实用的工具类,包括了字符串处理、集合操作、函数式编程、并发框架等。而IntMath类是Guava中的一个数学工具类,其中的gcd(int a, int b)方法用于计算a和b的最大公约数。

算法简介

最大公约数(Greatest Common Divisor,简称gcd)是指多个整数公有的约数中最大的一个。例如,8和12的最大公约数是4,因为8和12都能被4整除,而没有比4更大的公约数。

计算最大公约数有多种算法,最著名的几种包括辗转相减法、欧几里得算法和更相减损法。其中,欧几里得算法也叫做辗转相除法,它利用了两个整数的余数相同,其gcd也相同的规律。

算法实现

IntMath类的gcd(int a, int b)方法实现了欧几里得算法。具体来说,算法流程如下:

  1. 如果b等于0,返回a;否则,执行步骤2。
  2. 计算a和b的余数r,将a赋值为b,将b赋值为r,然后执行步骤1。

这个算法的正确性可以通过数学归纳法证明。由于该方法使用了除法和取余运算,它会比较慢。因此,在Guava中,gcd(int a, int b)方法还提供了一个更快的版本gcd(int a, int b, int c),它利用了辗转相减法和位运算来计算最大公约数。

代码片段

下面是IntMath类的gcd(int a, int b)方法的代码片段:

/**
 * Returns the greatest common divisor of {@code a,} {@code b}.
 *
 * <p><b>Note:</b> The result is always positive. If either {@code a} or {@code b} is {@code
 * Integer.MIN_VALUE}, this method will throw an {@link ArithmeticException} because the result
 * would be greater than {@code Integer.MAX_VALUE}.
 *
 * @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
 */
@GwtIncompatible // TODO
public static int gcd(int a, int b) {
  /*
   * The reason we require both arguments to be >= 0 is because otherwise, what do you return on
   * gcd(0, Integer.MIN_VALUE)? BigInteger.gcd would return positive 2^31, but positive 2^31
   * isn't an int.
   */
  checkNonNegative("a", a);
  checkNonNegative("b", b);
  if (a == 0) {
    // 0 % b == 0, so b divides a, but the converse doesn't hold.
    // BigInteger.gcd is consistent with this decision.
    return b;
  } else if (b == 0) {
    return a; // similar logic
  }
  /*
   * Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
   * This is >60% faster than the Euclidean algorithm in benchmarks.
   */
  int aTwos = Integer.numberOfTrailingZeros(a);
  a >>= aTwos; // divide out all 2s
  int bTwos = Integer.numberOfTrailingZeros(b);
  b >>= bTwos; // divide out all 2s
  while (a != b) {
    // Both a, b are odd. Swap if necessary so a <= b, then set b = b - a (which is even).
    if (a > b) {
      int tmp = b;
      b = a;
      a = tmp;
    }
    b -= a;
    b >>= Integer.numberOfTrailingZeros(b); // b is now even
  }
  return a << Math.min(aTwos, bTwos);
}

这个代码片段除了提供了gcd(int a, int b)方法的实现之外,还包含了一些异常检查和处理。由于IntMath类的源码使用了Guava自定义的注解@GwtIncompatible,因此该代码片段可能不能在Google Web Toolkit(GWT)中使用,但在其他Java应用程序中都可以。