Java中欧几里德算法的最大公约数GCD

问题描述

我为Greatest Common Divisor- GCD编写了此代码。 我从较大的整数中减去较小的整数,然后从最大的整数中减去较小的整数,然后再次从较大的整数中减去较小的整数,直到两个整数相等为止。 我想知道这是否正确, 是否可以使其更简单? 谢谢。

public static void main(String[] args) {
    int firstInteger=114,secondInteger=67;


    if (firstInteger>secondInteger) {

        int result=firstInteger-secondInteger;

        while (firstInteger != secondInteger) {

            if (secondInteger > result) {
                firstInteger = secondInteger;
                secondInteger = result;
                result = firstInteger - secondInteger;
            } else {
                firstInteger = result;
                result = firstInteger - secondInteger;
            }
        }
        System.out.println(firstInteger);
    }
    else {

        int result=secondInteger-firstInteger;

        while (secondInteger!=firstInteger) {

            if (firstInteger>result)  {
                secondInteger=firstInteger;
                firstInteger=result;
                result=secondInteger-firstInteger;

            }
            else {
                secondInteger=result;
                result=secondInteger-firstInteger;
            }
        }
        System.out.println(secondInteger);
    }


}

解决方法

态度是正确的,并且代码将按预期运行,但是,如果将0用作值firstIntegersecondInteger,它将失败(锁定为连续循环)。有符号整数值也是如此。如果它们出现,您将需要处理这些情况。

尽管对于要执行的任务来说,代码很长,但它确实可以工作。如果您使用不同的概念来处理任务,例如,可以利用Modulo(%)运算符(也称为 Remainder Operator )并执行除法形式来将其大大缩短看看是否有余数,而不是进行减法,并忽略以哪个较大的参数值开头。这是一个实际上可以用作方法的示例:

public static int getGreatestCommonDivisor(int numerator,int denominator) {
    if (numerator <= 0 || denominator <= 0) {
        System.err.println("getGreatestCommonDivisor() Method Error! A value of "
                         + "zero (0) or less can not be supplied as an argument!");
        return -1;
    }
    int temp = numerator % denominator;
    while (temp > 0) {
        numerator = denominator;
        denominator = temp;
        temp = numerator % denominator;
    }
    return denominator;
}

如果要在方法内部处理带符号的参数值,则可以使用Math#abs()方法,该方法返回 int 值的绝对(正)值。此方法给出参数的绝对值。参数可以是int,double,long和float,但是对于此方法,我们只关心 int 类型的参数。这是一个示例:

public static int getGreatestCommonDivisor(final int numerator,final int denominator) {
    if (numerator == 0 || denominator == 0) {
        System.err.println("greatestCommonDivisor() Method Error! A value of "
                         + "zero (0) can not be supplied as an argument!");
        return -1;
    }
    int num = numerator;
    num = Math.abs(numerator);          // Ensure an absolute value
    int gcd = Math.abs(denominator);    // Ensure an absolute value
    int temp = num % gcd;
    while (temp > 0) {
        num = gcd;
        gcd = temp;
        temp = num % gcd;
    }
    return gcd;
}
,

您的代码确实有效。下面是我编写的程序。

    public int calculateGCD(int highNumber,int lowNumber){
        boolean GCDFound = false;
        int quotient,remainder,GCD = 1;
         while(!GCDFound)
         {
            quotient = highNumber / lowNumber;
            remainder = Math.floorMod(highNumber,lowNumber);
            if(remainder == 0)
            {
                GCD = lowNumber;
                GCDFound = true;
            }
            else
            {
                highNumber = lowNumber;
                lowNumber = remainder;
            }
         }
         return GCD;
}`

没有错误处理。数字既不为零也不为零。

我在您的(kamilP)代码和我的代码上完成了三个测试。每个测试使用1,000,000个数字对的二维数组。第一个数组编号在1到107,374,143之间,第二个数组编号在107,143和2,147,483,646之间,第三个数组编号在1和2,646之间。测试程序程序通过数组需要多长时间。

结果如下(以毫秒为单位): KamilP和CombatWomble

  • 数组1273ms 155ms
  • 数组2274ms 175ms
  • 数组3285ms 173ms

这是我使其变得更简单,更快的方式。

,

是否可以简化?

有几种方法可以简化它。这是三个。

  • 第一种情况会修改您的算法。我没有进行性能分析,因为它需要诸如JMH之类的东西,但我尚未安装。
  • 所有案例都处理正值和负值。
  • 数学会自动调整分子和分母,因此调用方法时rs的顺序无关紧要。
  • 第二种方法和第三种方法使用Euclids Algorithm
  • 这两个方法都将在被0除时抛出异常。

在您的方法中,我使用了一个循环并更正了两个值 以确保在减法过程中取得积极结果。

public static int gcd(int r,int s) {
      // absolute value of r and s
      r = r > 0 ? r : -r;
      s = s > 0 ? s : -s;

      while (s > 0) {
          // find min(r,s)
          int t = r > s ? s : r;

          // find max(r,s)
          r = r > s ? r : s;

          s = t;
          r = r - s;
      }
      return r;
}

第二种方法是简单的迭代,可能是最有效的。但是,返回GCD之前必须更正该标志。

public static int gcd(int r,int s) {
    while (s != 0) {
        int t = r % s;
        r = s;
        s = t;
    }
    return r > 0 ? r : -r;
}

这是递归方法。再次需要纠正标志。

public static int gcd(int r,int s) {
    if (s != 0) {
        return gcd(s,r % s);
    }
    return r > 0 ? r : -r;
}

这里是对顺序和符号可能变化的测试。

System.out.println(gcd(24,36));
System.out.println(gcd(-24,36));
System.out.println(gcd(24,-36));
System.out.println(gcd(-24,-36));
System.out.println(gcd(36,24));
System.out.println(gcd(-36,-24));
System.out.println(gcd(36,-24));
System.out.println(gcd(-36,24));

所有三种方法都会打印。

12
12
12
12
12
12
12
12