나는 그런 기능이 존재 함을 알 한 BigInteger
예 BigInteger#gcd
. 다른 유형 ( int
, long
또는 Integer
) 에서도 작동하는 Java에 다른 기능이 있습니까? 이것은 java.lang.Math.gcd
(모든 종류의 과부하와 함께) 이해가 될 것 같지만 거기에는 없습니다. 다른 곳에 있습니까?
(이 질문을 "내가 직접 구현하는 방법"과 혼동하지 마십시오!)
나는 그런 기능이 존재 함을 알 한 BigInteger
예 BigInteger#gcd
. 다른 유형 ( int
, long
또는 Integer
) 에서도 작동하는 Java에 다른 기능이 있습니까? 이것은 java.lang.Math.gcd
(모든 종류의 과부하와 함께) 이해가 될 것 같지만 거기에는 없습니다. 다른 곳에 있습니까?
(이 질문을 "내가 직접 구현하는 방법"과 혼동하지 마십시오!)
답변:
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();
}
BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).intValue()
훨씬 낫습니다.
내가 아는 한, 프리미티브에 대한 내장 메소드는 없습니다. 그러나 이렇게 간단한 것이 트릭을 수행해야합니다.
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); }
동일한 바이트 코드로 컴파일하기 때문에 둘 사이에는 전혀 차이가 없다는 점에 유의해야합니다 .
또는 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;
}
Jakarta Commons Math는 정확히 그것을 가지고 있습니다.
이 바이너리 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
여기의 일부 구현은 두 숫자가 모두 음수이면 제대로 작동하지 않습니다. 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);
}
a
하고 b
있다 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);
0 인수에 대해 동작이 진정으로 대칭이되도록 사용 하는 것이 좋습니다 .
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));
}
}
Java 1.5 이상을 사용 Integer.numberOfTrailingZeros()
하는 경우 필요한 검사 및 반복 횟수를 줄이는 데 사용하는 반복 바이너리 GCD 알고리즘입니다 .
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 );
}
}
}
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;
}
이 방법은 Euclid의 알고리즘을 사용하여 두 정수의 "Greatest Common Divisor"를 얻습니다. 두 개의 정수를 받고 그 gcd를 반환합니다. 간단합니다!
/*
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
}
}
Commons-Math 와 Guava에서 제공하는 GCD 기능 에는 약간의 차이가 있습니다.
ArithematicException.class
for Integer.MIN_VALUE
또는 Long.MIN_VALUE
.
IllegalArgumentException.class
모든 음수 값에 대해를 던집니다 .%는 우리에게 gcd를 제공 할 것입니다. 두 숫자 사이의 의미는 다음과 같습니다 .- % 또는 big_number / small_number의 mod는 = gcd이고, 우리는 다음과 같이 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;
}
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;
}
gcd(42, 30)
그래야 6
하지만 12
귀하의 예에 의한 것입니다. 그러나 12는 30과 42의 제수가 아닙니다 gcd
. 재귀 적으로 호출해야합니다 . Matt의 답변을 보거나 Euclidean 알고리즘에 대한 Wikipedia를 참조하십시오.