Java中更快的GCD(n,m)?

Java中更快的GCD(n,m)?,java,algorithm,greatest-common-divisor,Java,Algorithm,Greatest Common Divisor,我正在做一些需要大量使用GCD算法的事情,我希望它能尽快完成。我试过普通方法、二进制方法和一种记忆方法,我认为这种方法比它更有效。我从中复制了二进制方法,只做了一些小的调整 我一直在使用一个名为TestGCD的类进行测试,整个过程如下: import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestGCD { privat

我正在做一些需要大量使用GCD算法的事情,我希望它能尽快完成。我试过普通方法、二进制方法和一种记忆方法,我认为这种方法比它更有效。我从中复制了二进制方法,只做了一些小的调整

我一直在使用一个名为TestGCD的类进行测试,整个过程如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestGCD
{
  private static class Pair<A>
  {
    private final A a_one;
    private final A a_two;

    public Pair(A a_one, A a_two)
    {
      this.a_one = a_one;
      this.a_two = a_two;
    }

    @Override
    public boolean equals(Object object)
    {
      if (this == object)
        return true;
      if (object == null)
        return false;
      if (!(object instanceof Pair))
        return false;

      final Pair other = (Pair) object;

      if (a_one == null)
        if (other.a_one != null)
          return false;
      if (a_two == null)
        if (other.a_two != null)
          return false;
      if (a_one.equals(other.a_one))
        if (a_two.equals(other.a_two))
          return true;
      if (a_one.equals(other.a_two))
        if (a_two.equals(other.a_one))
          return true;

      return false;
    }

    public A getFirst()
    {
      return a_one;
    }

    public A getSecond()
    {
      return a_two;
    }

    @Override
    public int hashCode()
    {
      final int prime = 31;
      int result = 1;

      final int aOneHash = a_one == null ? 0 : a_one.hashCode();
      final int aTwoHash = a_two == null ? 0 : a_two.hashCode();

      int resultOneWay = prime * result + aOneHash;
      resultOneWay += prime * result + aTwoHash;

      int resultOtherWay = prime * result + aTwoHash;
      resultOtherWay += prime * result + aOneHash;

      result += resultOneWay + resultOtherWay;
      return result;
    }

    @Override
    public String toString()
    {
      return String.format("%s, %s", a_one, a_two);
    }
  }

  private final static Map<Pair<Integer>, Integer> STORAGE = new HashMap<>();

  private static void addNewPairs(List<Pair<Integer>> newPairs, int result)
  {
    for (final Pair<Integer> pair : newPairs)
      STORAGE.put(pair, result);
  }

  private static int gcd(int x, int y)
  {
    if (x == 0)
      return y;
    if (y == 0)
      return x;

    int gcdX = Math.abs(x);
    int gcdY = Math.abs(y);

    if (gcdX == 1 || gcdY == 1)
      return 1;

    while (gcdX != gcdY)
      if (gcdX > gcdY)
        gcdX -= gcdY;
      else
        gcdY -= gcdX;

    return gcdX;
  }

  private static int gcdBinary(int x, int y)
  {
    int shift;

    /* GCD(0, y) == y; GCD(x, 0) == x, GCD(0, 0) == 0 */
    if (x == 0)
      return y;
    if (y == 0)
      return x;

    int gcdX = Math.abs(x);
    int gcdY = Math.abs(y);

    if (gcdX == 1 || gcdY == 1)
      return 1;

    /* Let shift := lg K, where K is the greatest power of 2 dividing both x and y. */
    for (shift = 0; ((gcdX | gcdY) & 1) == 0; ++shift)
    {
      gcdX >>= 1;
      gcdY >>= 1;
    }

    while ((gcdX & 1) == 0)
      gcdX >>= 1;

    /* From here on, gcdX is always odd. */
    do
    {
      /* Remove all factors of 2 in gcdY -- they are not common */
      /* Note: gcdY is not zero, so while will terminate */
      while ((gcdY & 1) == 0)
        /* Loop X */
        gcdY >>= 1;

      /*
       * Now gcdX and gcdY are both odd. Swap if necessary so gcdX <= gcdY,
       * then set gcdY = gcdY - gcdX (which is even). For bignums, the
       * swapping is just pointer movement, and the subtraction
       * can be done in-place.
       */
      if (gcdX > gcdY)
      {
        final int t = gcdY;
        gcdY = gcdX;
        gcdX = t;
      }  // Swap gcdX and gcdY.
      gcdY = gcdY - gcdX;                       // Here gcdY >= gcdX.
    }while (gcdY != 0);

    /* Restore common factors of 2 */
    return gcdX << shift;
  }

  private static int gcdMemoised(int x, int y)
  {
    if (x == 0)
      return y;
    if (y == 0)
      return x;

    int gcdX = Math.abs(x);
    int gcdY = Math.abs(y);

    if (gcdX == 1 || gcdY == 1)
      return 1;

    final List<Pair<Integer>> newPairs = new ArrayList<>();
    while (gcdX != gcdY)
    {
      final Pair<Integer> pair = new Pair<>(gcdX, gcdY);
      final Integer result = STORAGE.get(pair);
      if (result != null)
      {
        addNewPairs(newPairs, result);
        return result;
      }
      else
        newPairs.add(pair);

      if (gcdX > gcdY)
        gcdX -= gcdY;
      else
        gcdY -= gcdX;
    }

    addNewPairs(newPairs, gcdX);

    return gcdX;
  }
import java.util.ArrayList;
导入java.util.HashMap;
导入java.util.List;
导入java.util.Map;
公共类TestGCD
{
私有静态类对
{
私人决赛;
私人决赛A_2;
公共对(A_1,A_2)
{
this.a_one=a_one;
this.a_two=a_two;
}
@凌驾
公共布尔等于(对象)
{
if(this==对象)
返回true;
if(object==null)
返回false;
if(!(对象实例对))
返回false;
最后一对其他=(对)对象;
if(a_one==null)
if(other.a_one!=null)
返回false;
if(a_two==null)
if(other.a_two!=null)
返回false;
如果(a_一等于(其他a_一))
如果(a_2.等于(其他a_2))
返回true;
如果(a_一等于(其他a_二))
如果(a_2.等于(其他a_1))
返回true;
返回false;
}
公共A getFirst()
{
返回一个;
}
公共A getSecond()
{
返回a_2;
}
@凌驾
公共int hashCode()
{
最终整数素数=31;
int结果=1;
final int aOneHash=a_one==null?0:a_one.hashCode();
final int-aTwoHash=a_-two==null?0:a_-two.hashCode();
int resultonway=prime*result+aOneHash;
resultonway+=prime*result+aTwoHash;
int resultOtherWay=prime*result+aTwoHash;
resultOtherWay+=prime*result+aOneHash;
结果+=结果路径+结果路径;
返回结果;
}
@凌驾
公共字符串toString()
{
返回String.format(“%s,%s”,a\u-one,a\u-two);
}
}
私有最终静态映射存储=新HashMap();
私有静态void addNewPairs(列出新对,int结果)
{
for(最后一对:新对)
存储。放置(配对、结果);
}
专用静态整数gcd(整数x,整数y)
{
如果(x==0)
返回y;
如果(y==0)
返回x;
int gcdX=数学绝对值(x);
int gcdY=数学绝对值(y);
如果(gcdX==1 | | gcdY==1)
返回1;
while(gcdX!=gcdY)
如果(gcdX>gcdY)
gcdX-=gcdY;
其他的
gcdY-=gcdX;
返回gcdX;
}
专用静态int-gcdBinary(int x,int y)
{
int移位;
/*GCD(0,y)=y;GCD(x,0)=x,GCD(0,0)=0*/
如果(x==0)
返回y;
如果(y==0)
返回x;
int gcdX=数学绝对值(x);
int gcdY=数学绝对值(y);
如果(gcdX==1 | | gcdY==1)
返回1;
/*让移位:=lg K,其中K是2除以x和y的最大幂*/
对于(shift=0;((gcdX | gcdY)&1)==0;++shift)
{
gcdX>>=1;
gcdY>>=1;
}
而((gcdX&1)==0)
gcdX>>=1;
/*从现在开始,gcdX总是很奇怪*/
做
{
/*删除gcdY中2的所有因子——它们并不常见*/
/*注意:gcdY不是零,因此while将终止*/
而((gcdY&1)==0)
/*环X*/
gcdY>>=1;
/*
*现在gcdX和gcdY都是奇数。如有必要,交换gcdX和gcdY)
{
最终整数t=gcdY;
gcdY=gcdX;
gcdX=t;
}//交换gcdX和gcdY。
gcdY=gcdY-gcdX;//这里gcdY>=gcdX。
}而(gcdY!=0);
/*恢复2的公共因子*/
返回gcdX(gcdY)
gcdX-=gcdY;
其他的
gcdY-=gcdX;
}
addNewPairs(newPairs,gcdX);
返回gcdX;
}

那么,有没有办法让这个算法更快,或者说原始版本是我能得到的最快的算法呢?请不要建议使用另一种语言,我正在寻找算法的改进。显然,我的回忆录尝试完全失败了,但也许这里有人可以看到它的缺陷/改进。

你可以使用欧几里得算法。它的实现非常简单,而且效率更高。下面是它的代码:

static int gcd(int a, int b) {
    while (b != 0) {
        int t = a;
        a = b;
        b = t % b;
    }
    return a;
}

时间复杂度是
O(log(A+B))
,而您使用的算法是
O(A+B)
。它的伸缩性更好,对于较小的
a
b
也很有效。

您可以使用欧几里德算法。它的实现非常简单,而且效率更高。下面是它的代码:

static int gcd(int a, int b) {
    while (b != 0) {
        int t = a;
        a = b;
        b = t % b;
    }
    return a;
}

时间复杂度是
O(log(A+B))
,而您使用的算法是
O(A+B)
。它的伸缩性更好,对于小型
a
b
也很有效。

以下是我的想法,与@ILoveCoding相同

public static long gcd(long first, long second) {

    long big = 0;
    long small = 0;

    if(first > second) {
        big=first;
        small=second;
    }
    else {
        big=second;
        small=first;
    }

    long temp = big % small;
    while( (temp) > 1 ) {
        big = small;
        small = temp;
        temp = big % small;
    }

    if( temp == 0 ) {
        return small ;
    }
    else if( temp == 1) {
        return 1;
    }
    else {
        return -1; // will never occur. hack for compilation error.
    }

}
编辑:测试用例

System.out.println( gcd(10L, 5L));
System.out.println( gcd(11L, 7L));
System.out.println( gcd(15L, 21L));
System.out.println( gcd(-2L, -5L));
System.out.println( gcd(-2L, 2L));

以下是我的想法,与@ILoveCoding的思路相同

public static long gcd(long first, long second) {

    long big = 0;
    long small = 0;

    if(first > second) {
        big=first;
        small=second;
    }
    else {
        big=second;
        small=first;
    }

    long temp = big % small;
    while( (temp) > 1 ) {
        big = small;
        small = temp;
        temp = big % small;
    }

    if( temp == 0 ) {
        return small ;
    }
    else if( temp == 1) {
        return 1;
    }
    else {
        return -1; // will never occur. hack for compilation error.
    }

}
编辑:测试用例

System.out.println( gcd(10L, 5L));
System.out.println( gcd(11L, 7L));
System.out.println( gcd(15L, 21L));
System.out.println( gcd(-2L, -5L));
System.out.println( gcd(-2L, 2L));
问题(基于减法的版本)和公认答案(基于mod)的作者所使用的这两种方法似乎都不如它有效,所以这里是java代码(取自wikipidea)

静态长gcd(长u、长v){
int移位;
如果(u==0)返回v;
如果(v==0)返回u;
对于(移位=0;((u|v)&1)==0;++移位){
u>>=1;
v>>=1;
}
而((u&1)==0){
u>>=1;
}
做{
而((v&1)==0){
v>>=1;
}
如果(u>v){
长t=v;
v=u;
u=t;
}
v=v-u;
}而(v!=0);
问题(基于减法的版本)和公认答案(基于mod)的作者使用的return u似乎都不如,所以这里是java代码(取自wikipidea)

静态长gcd(长u、长v){
int移位;
如果(u==0)返回v;
如果(v==0)返回u;
对于(移位=0;((u|v