JavaRush /Java Blog /Random-JA /Java プログラミングの階乗関数

Java プログラミングの階乗関数

Random-JA グループに公開済み
今日は階乗について話します。これは、プログラマーが知っておく必要があると同時に、それを操作できるようにする必要がある最も基本的な関数の 1 つです。それでは始めましょう。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 についてのもう 1 つの小さなルール:
!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 が得られます。

再帰的な解決策

再帰とは、それ自体でメソッドを呼び出すことによって何らかのロジックを実行することです。この方法は再帰的と呼ばれます。通常、これは 2 つの部分で構成されます。
  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();
  }
}
ここでは特別なクラス IntStream を使用します。これは、int 値からのストリームを操作するときに追加機能を提供します。このようなストリームを作成するには、その静的メソッド rangeClosed を使用します。これは、2 から f までの値を 1 ステップで作成します。次に、reduce メソッドを使用してすべての値を結合します。つまり、その中でどのようにするかを示します。それらを組み合わせたいと考えています。最後に、getAsInt ターミナル メソッドを使用して結果の値を取得します。

BigInteger の使用

Java では、数値、特に BIG 数値を処理するためにBigIntegerクラスがよく使用されます。結局のところ、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 に設定します。 multiply - 以前の階乗値と現在の数値の間の乗算。

再帰的な解決策

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 が異なります。ストリームには、mapToObj メソッドがあり、これを使用して int 値を BigInteger に変換し、その後 multiply を使用してそれらを乗算します (オプションのラッパーからオブジェクトを取得するために get を追加しました)。これら 3 つのメソッドのいずれかを引数 100 で実行すると、オーバーフローは発生せず、次の結果が得られます。

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION