2010-10-24 12 views
65

Я видел, что такая функция существует для BigInteger, то есть BigInteger#gcd. Существуют ли другие функции на Java, которые также работают для других типов (int, long или Integer)? Кажется, это имеет смысл как java.lang.Math.gcd (со всеми видами перегрузок), но его там нет. Это где-то еще?Java: получить наибольший общий делитель


(Не путайте этот вопрос «как мне это реализовать себя», пожалуйста!)

+5

Почему принятый ответ один, который говорит вам, как осуществить это самостоятельно - хотя оберточной существующую реализацию? =) – djjeck

+0

Я согласен с вашим наблюдением. GCD должен иметь класс с множеством перегруженных статических методов, который принимает два числа и дает ему gcd. И он должен быть частью пакета java.math. – anu

ответ

60

Для междунар и долго, как примитивы, а не на самом деле. Для Integer, возможно, кто-то написал один.

Учитывая, что BigInteger является (математическим/функциональным) супермножеством int, Integer, long и Long, если вам нужно использовать эти типы, конвертировать их в BigInteger, делать GCD и преобразовывать результат обратно.

private static int gcdThing(int a, int b) { 
    BigInteger b1 = new BigInteger(""+a); // there's a better way to do this. I forget. 
    BigInteger b2 = new BigInteger(""+b); 
    BigInteger gcd = b1.gcd(b2); 
    return gcd.intValue(); 
} 

Лучший способ:

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(); 
} 
+49

'BigInteger.valueOf (a) .gcd (BigInteger.valueOf (b)). IntValue()' намного лучше. – Albert

+0

'valueOf()' ... круто, спасибо. –

+0

Некоторые критерии: https://stackoverflow.com/questions/21570890/java-get-greatest-common-divisor-which-method-is-better –

113

Насколько я знаю, не существует какой-либо встроенный метод для примитивов. Но что-то же просто, как это следует сделать трюк:

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

Вы можете также одна линия, если вы в такого рода вещи:

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

Следует отметить, что абсолютно no Разница между ними при компиляции одного и того же байтового кода.

+1

Это похоже на работу. Если это так, это потрясающе, lol. –

+0

Насколько я могу судить, это прекрасно работает. Я просто запускал 100 000 случайных чисел, хотя оба метода, и они соглашались каждый раз. –

+14

Это алгоритм Евклида ... Он очень старый и доказал свою правоту. Http: //en.wikipedia.org/wiki/Euclidean_algorithm – Rekin

33

Или алгоритм Евклида для вычисления НОД ...

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

Просто уточнить: это абсолютно не то, о чем я просил. – Albert

+10

В этом случае вы не указали, что вам не нужны альтернативные реализации, поскольку их не было. Только позже вы отредактировали свое сообщение, не ища реализации. Я считаю, что другие ответили «нет» более чем адекватно. – Xorlev

+3

Хорошее решение. +1 – Confuse

-11
int n1 = 12; // you can make the user insert n1,n2 using Scanner or JOptionPane 
int n2 = 26; 
int gcd = 1; 
int k = 1; 

while ((k <= n1) && (k <= n2)) { 
    if ((n1 % k == 0) && (n2 % k == 0)) { 
     gcd = k; 
    } 
    k++; 
} 

System.out.print("The Greatest Common divisor of The Two numbers IS : " + gcd); 
+3

1. Я прямо сказал в своем вопросе, что не ищу алгоритм, потому что я знаю, как его реализовать сам. 2. Ваш алгоритм работает очень плохо. Вы не должны так делать! Сравните его с [евклидовым алгоритмом] (http://en.wikipedia.org/wiki/Euclidean_algorithm) и угадайте, какой из них требует меньше шагов, например, для чисел 100000 и 100001. – Albert

+1

1.I не знаю, что вы видели мой ответ или нет. но это НЕ алгоритм. Это очень простой ответ, а не медленный, вы можете попробовать. – user2003749

+4

Это медленно. Может быть, не на ваших двух входных входах, а на 'O (_value_ меньшего числа)', что ужасно. Учитывая, что лучшая альтернатива известна буквально на протяжении тысячелетий, я не понимаю, почему эквивалент пробного деления когда-либо был чем-то нужным. –

-3

% собирается дать нам НОД между двумя числами, это означает: - % или мод из big_number/small_number являются = НОД, и записать его на Java, как это big_number % small_number ,

EX1: два целых

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

ЕХ2: три целых

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' рекурсивно. См. Ответ Мэтта или посмотрите на Википедию для евклидова алгоритма. – Albert

5

Вы можете использовать эту реализацию Binary GCD algorithm

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

}

F ром http://introcs.cs.princeton.edu/java/23recursion/BinaryGCD.java.html

+0

И почему это работает? – Deep

+0

Это вариант алгоритма Штейна, который использует это на большинстве машин, а смещение - относительно дешевая операция. Это стандартный алгоритм. –

9

Использование гуавы LongMath.gcd() и IntMath.gcd()

+1

Интересно, что Guava не использует евклидовой метод «modulo», а бинарный алгоритм GCD, который, по их утверждению, на 40% быстрее. Можно с уверенностью сказать, что он довольно эффективен и хорошо протестирован. –

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

Один краевой случай для этого - если '' и '' '' 'Integer.MIN_VALUE', вы получите' Integer.MIN_VALUE' назад в качестве результата, что отрицательно. Это может быть приемлемым. Проблема состоит в том, что gcd (-2^31, -2^31) = 2^31, но 2^31 не может быть выражено как целое число. –

+0

Я бы также рекомендовал использовать 'if (a == 0 || b == 0) return Math.abs (a + b);' так, чтобы поведение было действительно симметричным для нулевых аргументов. –

2

Если вы используете Java 1.5 или более поздней версии, то это итеративный бинарный алгоритм НОД, который использует 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); 
     } 
    } 
} 
+0

Похожие на MutableBigInteger.binaryGcd (int, int), к сожалению, последний недоступен. Но все равно здорово! –

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 
    } 
} 
+0

Можете ли вы подробно объяснить, как это может помочь? – kommradHomer

4

Если я не имею Guava, я определяю так:

int gcd(int a, int b) { 
    return a == 0 ? b : gcd(b % a, a); 
} 
0
import java.util.*; 

public class BCD { 

    public static void main(String[] args) { 
     int k=1; 
     Scanner in = new Scanner(System.in); 
     int x = in.nextInt(); 
     int y = in.nextInt(); 
     for(int i=1;i<=Math.min(x,y);i++){ 
      if(x%i==0 && y%i==0) 
       k=i; 
     } 
     System.out.println("the biggest common divisor is " + k); 
    } 
} 
+0

Этот метод работает, но занимает очень много времени, когда x и y - большие простые числа. –

0

Я использовал следующий метод.

/** 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 

    // First number 
    int n1 = 16; 
    // Second number 
    int n2 = 24; 
    // Greatest Common Divisor 
    int gdk = 0; 

    for (int k = 2; k <= n1 && k <= n2; k++){ 
     if(n1 % k == 0 && n2 % k == 0){ 
      gdk = k; 
     } 
    } 

    System.out.println(gdk); 
} 
+0

Этот метод работает, но занимает очень много времени, когда n1 и n2 - большие простые числа. –

0
import java.util.*; 
public class Greatest_common_Divisor 
{ 

    public static void main (String[]args){ 
      Scanner input = new Scanner(System.in); 
    System.out.println("Enter two integers: "); 
    int n1 = input.nextInt(); 
    int n2 = input.nextInt(); 

    int d = 0; 
    int e=0; 
    int temp = 0; 
    //finds the lowest value 
    if(n1 < n2) { 
     temp = n1; 
     n1 = n2; 
     n2 = temp; 
    } 

    for(d = n2;(n2%d!=0 || n1%d!= 0);d--){ 


    } 

    System.out.println("The Greatest Common Divisor of " + n1 + " and " + n2 + " is " + d); 

    } 

} 
Смежные вопросы