JavaRush /Java Blog /Random-KO /Java 프로그래밍의 팩토리얼

Java 프로그래밍의 팩토리얼

Random-KO 그룹에 게시되었습니다
오늘은 팩토리얼(factorial)에 대해 이야기해보겠습니다. 이것은 프로그래머가 알아야 하고 동시에 작업할 수 있어야 하는 가장 기본적인 기능 중 하나입니다. 그럼 시작해 보겠습니다. n의 계승은 1부터 n까지의 모든 자연수를 곱한 값(곱셈)이며, 이를 n! 모습:
1! =  1
2! =  1 * 2 = 2
3! =  1 * 2 * 3 = 6
4! =  1 * 2 * 3 * 4 = 24
5! =  1 * 2 * 3 * 4 * 5  = 120
그리고 0에 대한 작은 규칙이 하나 더 있습니다.
!0  = 1
예를 들어 계승차 6을 구하고 싶다면! 그리고 4!:
6!-4! = 1⋅2⋅3⋅4⋅5⋅6 - 1⋅2⋅3⋅4 = 720 - 24 = 696
이것이 Java에서 어떻게 보이는지 살펴보고 계승을 계산할 수 있는 여러 가지 방법을 이해해 보겠습니다.

일반적인 솔루션

public static int getFactorial(int f) {
  int result = 1;
  for (int i = 1; i <= f; i++) {
     result = result * i;
  }
  return result;
}
복잡한 것은 없습니다. 수신된 숫자를 주기의 크기로 사용합니다. 여기서 f에 도달할 때까지 이전의 모든 숫자를 곱합니다. 그리고 주요 내용은 다음과 같습니다.

System.out.println(getFactorial(6) - getFactorial(4));
확인하고 원하는 결과(696)를 얻습니다.

재귀적 솔루션

재귀는 자체적으로 메서드를 호출하여 일부 논리를 수행합니다. 이 방법을 재귀적이라고 합니다. 일반적으로 다음 두 부분으로 구성됩니다.
  1. 메소드 종료 조건에 도달하면 메소드 자체 호출을 중지하고 값 전달을 시작해야 합니다. 그렇지 않으면 자체적으로 메서드를 호출하여 무한 루프가 발생하고 결과적으로 StackOverflowError 가 발생합니다 .

  2. 주어진 상황에서 필요한 일부 처리(논리) + 자체 호출, 그러나 다른 수신 값을 사용합니다.

오늘날 재귀에 대한 이상적인 예는 계승을 찾는 것입니다.
public static int getFactorial(int f) {
  if (f <= 1) {
     return 1;
  }
  else {
     return f * getFactorial(f - 1);
  }
}
1에 도달할 때 재귀를 종료하기 위한 조건을 설정합니다. 인수가 1이 아닌 경우 현재 값에 이 메서드에 대한 다음 호출의 결과를 곱합니다(현재 값 -1을 보냅니다).

스트림을 이용한 솔루션

스트리밍 기능을 모르시는 분들이나 기억을 되살리고 싶은 분들은 이 글을 읽어보시면 도움이 될 것입니다 .
public static int getFactorial(int f) {
  if (f <= 1) {
     return 1;
  }
  else {
     return IntStream.rangeClosed(2, f).reduce((x, y) -> x * y).getAsInt();
  }
}
여기서는 int 값의 스트림으로 작업할 때 추가 기능을 제공하는 특수 클래스 IntStream을 사용합니다. 이러한 스트림을 생성하기 위해 우리는 1 단계로 2부터 f까지의 값을 생성하는 정적 메소드 rangeClosed를 사용합니다. 다음으로 감소 메소드를 사용하여 모든 값을 결합합니다. 즉, 방법을 보여줍니다. 우리는 그것들을 결합하고 싶습니다. 마지막으로 getAsInt 터미널 메소드를 사용하여 결과 값을 얻습니다.

BigInteger 사용

Java에서는 BigInteger 클래스가 숫자, 특히 BIG 숫자를 처리하는 데 자주 사용됩니다 . 결국, int를 사용한다면 데이터 손실 없이 취할 수 있는 최대 계승은 31(장기적으로는 39)입니다. 하지만 100의 계승이 필요하다면 어떻게 될까요? BigInteger를 사용하여 이전 솔루션을 살펴보겠습니다. Java 프로그래밍의 계승 - 2

일반적인 솔루션

public static BigInteger getFactorial(int f) {
  BigInteger result = BigInteger.ONE;
  for (int i = 1; i <= f; i++)
     result = result.multiply(BigInteger.valueOf(i));
  return result;
}
계산 알고리즘은 본질적으로 동일하지만 여기서는 BigInteger의 기능인 BigInteger.ONE을 사용하여 시작 값을 1로 설정합니다. 곱하기 - 이전 계승 값과 현재 숫자를 곱합니다.

재귀적 솔루션

public static BigInteger getFactorial(int f) {
  if (f <= 1) {
     return BigInteger.valueOf(1);
  }
  else {
     return BigInteger.valueOf(f).multiply(getFactorial(f - 1));
  }
}
BigInteger 작업을 위한 일부 메서드가 추가된다는 점을 제외하고 솔루션의 일반적인 논리는 변경되지 않습니다.

스트림을 이용한 솔루션

public static BigInteger getFactorial(int f) {
  if (f < 2) {
     return BigInteger.valueOf(1);
  }
  else {
     return IntStream.rangeClosed(2, f).mapToObj(BigInteger::valueOf).reduce(BigInteger::multiply).get();
  }
}
기본적으로 모든 것이 동일하지만 BigInteger를 사용합니다. 스트림에는 이제 int 값을 BigInteger로 변환하여 이후에 곱셈을 사용하여 함께 곱하는 mapToObj 메소드가 있습니다(음, Optional 래퍼 에서 객체를 가져오기 위해 get을 추가했습니다 ). 인수 100을 사용하여 이 세 가지 메서드 중 하나를 실행하면 오버플로가 발생하지 않으며 다음과 같은 결과를 얻습니다.

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION