web-dev-qa-db-fra.com

Java: obtenir le plus grand commun diviseur

J'ai vu qu'une telle fonction existe pour BigInteger, c'est-à-dire BigInteger#gcd . Existe-t-il d'autres fonctions dans Java qui fonctionnent également pour d'autres types (int, long ou Integer)? Il semble que cela aurait du sens comme Java.lang.Math.gcd (avec toutes sortes de surcharges) mais ce n’est pas là. Est-ce ailleurs?


(Ne confondez pas cette question avec "comment puis-je implémenter ceci moi-même", s'il vous plaît!)

73
Albert

Pour int et long, en tant que primitifs, pas vraiment. Pour Integer, il est possible que quelqu'un en ait écrit un.

Etant donné que BigInteger est un sur-ensemble (mathématique/fonctionnel) d'int, Integer, long et Long, si vous devez utiliser ces types, convertissez-les en BigInteger, effectuez le GCD et convertissez le résultat.

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();
}
67
Tony Ennis

Autant que je sache, il n'y a pas de méthode intégrée pour les primitives. Mais quelque chose d'aussi simple que cela devrait faire l'affaire:

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

Vous pouvez également utiliser une ligne si vous aimez ce genre de chose:

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

Il convient de noter qu’il existe absolument non différence entre les deux lorsqu’ils compilent le même code octet.

124
Matt

Ou l'algorithme euclidien de calcul du 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;
}
33
Xorlev

Utilisez Guava LongMath.gcd() et IntMath.gcd()

11
Morad

Jakarta Commons Math a exactement cela.

ArithmeticUtils.gcd (int p, int q)

11
Tom Tucker

Sauf si j'ai la goyave, je définis comme ceci:

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

Certaines implémentations ne fonctionnent pas correctement si les deux nombres sont négatifs. gcd (-12, -18) vaut 6, pas -6.

Donc, une valeur absolue doit être renvoyée, quelque chose comme

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

Vous pouvez utiliser cette implémentation de Algorithme GCD binaire

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));
}

}

De http://introcs.cs.princeton.edu/Java/23recursion/BinaryGCD.Java.html

6
linuxjava

nous pouvons utiliser la fonction récursive pour trouver 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
Esann

Si vous utilisez Java 1.5 ou une version ultérieure, il s'agit d'un algorithme GCD binaire itératif qui utilise Integer.numberOfTrailingZeros() pour réduire le nombre de vérifications et d'itérations nécessaires.

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;
    }
}

Test de l'unité:

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 );
        }
    }
}
2
MT0
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;
}

Cette méthode utilise l’algorithme d’Euclid pour obtenir le "plus grand commun diviseur" de deux entiers. Il reçoit deux entiers et en renvoie le gcd. c'est aussi simple que ça!

1
Mohsen
/*
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
  }
}
0
Gitau Harrison

J'ai utilisé cette méthode que j'ai créée à l'âge de 14 ans.

    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
John Doe

Est-ce ailleurs?

Apache! - il a à la fois gcd et lcm, trop cool!

Cependant, en raison de la profondeur de leur mise en œuvre, il est plus lent que la version manuscrite simple (si cela compte).

Les fonctions GCD fournies par Commons-Math et Guava présentent quelques différences.

  • Commons-Math lance un ArithematicException.class uniquement pour Integer.MIN_VALUE ou Long.MIN_VALUE.
    • Sinon, gère la valeur en tant que valeur absolue.
  • La goyave lance un IllegalArgumentException.class pour toutes les valeurs négatives.
0
Jin Kwon