Java:最大公約数を取得する


91

このような関数が、BigIntegerに存在することを確認しましたBigInteger#gcd。他のタイプ(intlongまたはInteger)でも機能するJavaの他の関数はありますか?これはjava.lang.Math.gcd(あらゆる種類のオーバーロードで)理にかなっているようですが、ありません。別の場所ですか?


(この質問を「自分で実装する方法」と混同しないでください!)


7
なぜ受け入れられた答えは、それを自分で実装する方法を教えてくれるものです-既存の実装をラップしていますが?=)
djjeck 2013年

私はあなたの観察に同意します。GCDは、2つの数値を受け取ってgcdを提供する一連のオーバーロードされた静的メソッドを持つクラスである必要があります。そして、それはjava.mathパッケージの一部であるべきです。
anu

回答:


79

intおよびlongの場合、プリミティブとしてではなく、実際に。Integerの場合、誰かが作成した可能性があります。

BigIntegerがint、Integer、long、およびLongの(数学/関数)スーパーセットであることを考えると、これらの型を使用する必要がある場合は、それらをBigIntegerに変換し、GCDを実行して、結果を元に戻します。

private static int gcdThing(int a, int b) {
    BigInteger b1 = BigInteger.valueOf(a);
    BigInteger b2 = BigInteger.valueOf(b);
    BigInteger gcd = b1.gcd(b2);
    return gcd.intValue();
}

63
BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).intValue()はるかに優れています。
アルバート


4
この関数が頻繁に(つまり、数百万回)呼び出される場合は、intまたはlongをBigIntegerに変換しないでください。プリミティブ値のみを使用する関数は、おそらく1桁速くなります。他の回答を確認してください。
jcsahnwaldt Reinstate Monica 2015

@Bhanu Pratap Singhキャストや切り捨てを回避するには、intとlongに別々のメソッドを使用することをお勧めします。私はそれに応じて答えを編集しました。
jcsahnwaldt Reinstate Monica 2015

1
これは質問に答えない(Javaではintまたはlongのgcdはどこにあるか)だけでなく、提案された実装はかなり非効率的です。これは受け入れられる答えではありません。私の知る限り、Javaランタイムにはありませんが、サードパーティのライブラリに存在します。
フロリアンF

134

私の知る限り、プリミティブの組み込みメソッドはありません。しかし、これでうまくいくはずです。

public int gcd(int a, int b) {
   if (b==0) return a;
   return gcd(b,a%b);
}

そのようなことに夢中になっている場合は、1行で入力することもできます。

public int gcd(int a, int b) { return b==0 ? a : gcd(b, a%b); }

同じバイトコードにコンパイルされるため、2つの間にまったく違いがないことに注意してください。


私の知る限り、問題なく動作します。両方の方法を使用して100,000個の乱数を実行したところ、両者は毎回同意しました。
Tony Ennis、

19
それはユークリッドのアルゴリズムです...それは非常に古く、証明されています。 en.wikipedia.org/wiki/Euclidean_algorithm
2010年

ええ、私はそれを少し見ることができますが、それを処理するためにもっと時間が必要です。私はそれが好きです。
Tony Ennis、

1
@アルバート、まあ、いつでもジェネリック型で試してみて、機能するかどうかを確認できます。私はただの考えだとは思いませんが、アルゴリズムは実験するためのものです。いくつかの標準ライブラリまたはクラスに関しては、私は見たことがありません。ただし、オブジェクトを作成するときに、それがint、longなどであることを指定する必要があります。
Matt

1
@アルバート、まあ、マットは実装を提供しましたが、自分でそれを動作させることができます。つまり、「より一般的な」方法です。:)
Bart Kiers、

33

または、GCDを計算するためのユークリッドアルゴリズム...

public int egcd(int a, int b) {
    if (a == 0)
        return b;

    while (b != 0) {
        if (a > b)
            a = a - b;
        else
            b = b - a;
    }

    return a;
}

3
はっきりさせておきますが、これは絶対に私が求めていたものではありません。
アルバート

11
この場合、代替の実装が存在しないため、代替の実装が不要であることを指定していませんでした。後になって、実装を探していない投稿を編集しました。他の人は十分に「いいえ」と答えていたと思います。
Xorlev、

2
aが非常に大きく、bが小さい場合、これは遅くなります。'%'ソリューションははるかに高速です。
Bruce Feist

12

2
興味深いことに、グアバはユークリッドの「モジュロ」法を使用していませんが、40%高速であると主張しているバイナリGCDアルゴリズムを使用しています。それはかなり効率的で十分にテストされていると言っても安全です。
フロリアンF

12

私がグアバでない限り、私はこのように定義します:

int gcd(int a, int b) {
  return a == 0 ? b : gcd(b % a, a);
}


7

Binary GCDアルゴリズムのこの実装を使用できます

public class BinaryGCD {

public static int gcd(int p, int q) {
    if (q == 0) return p;
    if (p == 0) return q;

    // p and q even
    if ((p & 1) == 0 && (q & 1) == 0) return gcd(p >> 1, q >> 1) << 1;

    // p is even, q is odd
    else if ((p & 1) == 0) return gcd(p >> 1, q);

    // p is odd, q is even
    else if ((q & 1) == 0) return gcd(p, q >> 1);

    // p and q odd, p >= q
    else if (p >= q) return gcd((p-q) >> 1, q);

    // p and q odd, p < q
    else return gcd(p, (q-p) >> 1);
}

public static void main(String[] args) {
    int p = Integer.parseInt(args[0]);
    int q = Integer.parseInt(args[1]);
    System.out.println("gcd(" + p + ", " + q + ") = " + gcd(p, q));
}

}

http://introcs.cs.princeton.edu/java/23recursion/BinaryGCD.java.htmlから


それは、ほとんどのマシンでシフトが比較的安価な操作であることを利用するスタインのアルゴリズムのバリエーションです。これは標準的なアルゴリズムです。
Bastian J

6

ここでのいくつかの実装は、両方の数値が負の場合、正しく機能しません。gcd(-12、-18)は6ではなく、6です。

したがって、次のような絶対値を返す必要があります

public static int gcd(int a, int b) {
    if (b == 0) {
        return Math.abs(a);
    }
    return gcd(b, a % b);
}

これの1つのエッジケースは、abが両方である場合、結果として返されInteger.MIN_VALUEますがInteger.MIN_VALUE、これはマイナスです。これは許容できる場合があります。問題はgcd(-2 ^ 31、-2 ^ 31)= 2 ^ 31ですが、2 ^ 31は整数として表現できません。
マイケルアンダーソン

if(a==0 || b==0) return Math.abs(a+b);引数がゼロの場合に動作が完全に対称になるように使用することもお勧めします。
マイケルアンダーソン

3

gcdを見つけるために再帰関数を使うことができます

public class Test
{
 static int gcd(int a, int b)
    {
        // Everything divides 0 
        if (a == 0 || b == 0)
           return 0;

        // base case
        if (a == b)
            return a;

        // a is greater
        if (a > b)
            return gcd(a-b, b);
        return gcd(a, b-a);
    }

    // Driver method
    public static void main(String[] args) 
    {
        int a = 98, b = 56;
        System.out.println("GCD of " + a +" and " + b + " is " + gcd(a, b));
    }
}

2

Java 1.5以降を使用している場合、これは反復バイナリGCDアルゴリズムでありInteger.numberOfTrailingZeros()、チェックと必要な反復の数を減らすために使用されます。

public class Utils {
    public static final int gcd( int a, int b ){
        // Deal with the degenerate case where values are Integer.MIN_VALUE
        // since -Integer.MIN_VALUE = Integer.MAX_VALUE+1
        if ( a == Integer.MIN_VALUE )
        {
            if ( b == Integer.MIN_VALUE )
                throw new IllegalArgumentException( "gcd() is greater than Integer.MAX_VALUE" );
            return 1 << Integer.numberOfTrailingZeros( Math.abs(b) );
        }
        if ( b == Integer.MIN_VALUE )
            return 1 << Integer.numberOfTrailingZeros( Math.abs(a) );

        a = Math.abs(a);
        b = Math.abs(b);
        if ( a == 0 ) return b;
        if ( b == 0 ) return a;
        int factorsOfTwoInA = Integer.numberOfTrailingZeros(a),
            factorsOfTwoInB = Integer.numberOfTrailingZeros(b),
            commonFactorsOfTwo = Math.min(factorsOfTwoInA,factorsOfTwoInB);
        a >>= factorsOfTwoInA;
        b >>= factorsOfTwoInB;
        while(a != b){
            if ( a > b ) {
                a = (a - b);
                a >>= Integer.numberOfTrailingZeros( a );
            } else {
                b = (b - a);
                b >>= Integer.numberOfTrailingZeros( b );
            }
        }
        return a << commonFactorsOfTwo;
    }
}

単体テスト:

import java.math.BigInteger;
import org.junit.Test;
import static org.junit.Assert.*;

public class UtilsTest {
    @Test
    public void gcdUpToOneThousand(){
        for ( int x = -1000; x <= 1000; ++x )
            for ( int y = -1000; y <= 1000; ++y )
            {
                int gcd = Utils.gcd(x, y);
                int expected = BigInteger.valueOf(x).gcd(BigInteger.valueOf(y)).intValue();
                assertEquals( expected, gcd );
            }
    }

    @Test
    public void gcdMinValue(){
        for ( int x = 0; x < Integer.SIZE-1; x++ ){
            int gcd = Utils.gcd(Integer.MIN_VALUE,1<<x);
            int expected = BigInteger.valueOf(Integer.MIN_VALUE).gcd(BigInteger.valueOf(1<<x)).intValue();
            assertEquals( expected, gcd );
        }
    }
}

MutableBigInteger.binaryGcd(int、int)と同様に、残念ながら後者にはアクセスできません。とにかくクール!
モストウスキー崩壊2016

2
public int gcd(int num1, int num2) { 
    int max = Math.abs(num1);
    int min = Math.abs(num2);

    while (max > 0) {
        if (max < min) {
            int x = max;
            max = min;
            min = x;
        }
        max %= min;
    }

    return min;
}

このメソッドは、ユークリッドのアルゴリズムを使用して、2つの整数の「最大公約数」を取得します。2つの整数を受け取り、それらのgcdを返します。とても簡単です!



0
/*
import scanner and instantiate scanner class;
declare your method with two parameters
declare a third variable;
set condition;
swap the parameter values if condition is met;
set second conditon based on result of first condition;
divide and assign remainder to the third variable;
swap the result;
in the main method, allow for user input;
Call the method;

*/
public class gcf {
    public static void main (String[]args){//start of main method
        Scanner input = new Scanner (System.in);//allow for user input
        System.out.println("Please enter the first integer: ");//prompt
        int a = input.nextInt();//initial user input
        System.out.println("Please enter a second interger: ");//prompt
        int b = input.nextInt();//second user input


       Divide(a,b);//call method
    }
   public static void Divide(int a, int b) {//start of your method

    int temp;
    // making a greater than b
    if (b > a) {
         temp = a;
         a = b;
         b = temp;
    }

    while (b !=0) {
        // gcd of b and a%b
        temp = a%b;
        // always make a greater than b
        a =b;
        b =temp;

    }
    System.out.println(a);//print to console
  }
}

これがどのように役立つかを説明で詳しく説明できますか?
kommradHomer 2016

0

私は14歳のときに作成したこの方法を使用しました。

    public static int gcd (int a, int b) {
        int s = 1;
        int ia = Math.abs(a);//<-- turns to absolute value
        int ib = Math.abs(b);
        if (a == b) {
            s = a;
        }else {
            while (ib != ia) {
                if (ib > ia) {
                    s = ib - ia;
                    ib = s;
                }else { 
                    s = ia - ib;
                    ia = s;
                }
            }
        }
        return s;
    }

0

Commons-MathGuavaが提供するGCD関数にはいくつかの違いがあります。

  • Commons-Mathは、またはに対してArithematicException.classのみスローします。 Integer.MIN_VALUELong.MIN_VALUE
    • それ以外の場合は、値を絶対値として扱います。
  • GuavaはIllegalArgumentException.class負の値に対してをスローします。

-3

%は、2つの数値の間にgcdを与えることを意味します。つまり、%またはbig_number / small_numberのmodは= gcdであり、次のようにJavaで記述します。 big_number % small_numberます。

EX1:2つの整数

  public static int gcd(int x1,int x2)
    {
        if(x1>x2)
        {
           if(x2!=0)
           {
               if(x1%x2==0)     
                   return x2;
                   return x1%x2;
                   }
           return x1;
           }
          else if(x1!=0)
          {
              if(x2%x1==0)
                  return x1;
                  return x2%x1;
                  }
        return x2;
        } 

EX2:3つの整数

public static int gcd(int x1,int x2,int x3)
{

    int m,t;
    if(x1>x2)
        t=x1;
    t=x2;
    if(t>x3)
        m=t;
    m=x3;
    for(int i=m;i>=1;i--)
    {
        if(x1%i==0 && x2%i==0 && x3%i==0)
        {
            return i;
        }
    }
    return 1;
}

2
これは間違っています。たとえば、間違っているgcd(42, 30)はずですが6、それは12あなたの例によるものです。ただし、12は30の除数ではなく、42の除数でもありませんgcd。再帰的に呼び出す必要があります。ユークリッドアルゴリズムについては、Mattの回答を参照するか、Wikipediaを参照してください。
アルバート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.