回答:
階乗用のライブラリー関数があると便利だとは思いません。効率的な階乗の実装については、かなりの研究があります。ここにいくつかの実装があります。
Apache Commons Mathには、MathUtilsクラスにいくつかの階乗メソッドがあります。
public class UsefulMethods {
public static long factorial(int number) {
long result = 1;
for (int factor = 2; factor <= number; factor++) {
result *= factor;
}
return result;
}
}
HoldOffHungerによるBig Numbersバージョン:
public static BigInteger factorial(BigInteger number) {
BigInteger result = BigInteger.valueOf(1);
for (long factor = 2; factor <= number.longValue(); factor++) {
result = result.multiply(BigInteger.valueOf(factor));
}
return result;
}
裸の裸の階乗が実際に必要になることはほとんどありません。ほとんどの場合、次のいずれかが必要になります。
1)ある階乗を別の階乗で割る、または
2)近似浮動小数点解。
どちらの場合も、シンプルなカスタムソリューションの方が適しています。
(1)の場合、x = 90の場合、/ 85!、90を保持する必要なく、x = 86 * 87 * 88 * 89 * 90と同じように結果を計算します。メモリ内:)
ケース(2)では、「スターリングの近似」をグーグル検索してください。
BigIntegerMath次のようにGuavaを使用します。
BigInteger factorial = BigIntegerMath.factorial(n);
階乗は初心者のプログラマにとってはいい練習になりますが、ほとんどの場合あまり役に立ちませんし、階乗関数の書き方を誰もが知っているため、通常、平均的なライブラリにはありません。
ルックアップテーブルを使用すると、これが最速の方法になると思います。
private static final long[] FACTORIAL_TABLE = initFactorialTable();
private static long[] initFactorialTable() {
final long[] factorialTable = new long[21];
factorialTable[0] = 1;
for (int i=1; i<factorialTable.length; i++)
factorialTable[i] = factorialTable[i-1] * i;
return factorialTable;
}
/**
* Actually, even for {@code long}, it works only until 20 inclusively.
*/
public static long factorial(final int n) {
if ((n < 0) || (n > 20))
throw new OutOfRangeException("n", 0, 20);
return FACTORIAL_TABLE[n];
}
ネイティブタイプlong(8バイト)の場合、最大で20!
20! = 2432902008176640000(10) = 0x 21C3 677C 82B4 0000
明らかに、21!オーバーフローを引き起こします。
したがって、ネイティブタイプのlong場合、最大で20!許可され、意味があり、正しいもののみです。
階乗は非常に急速に大きくなるため、再帰を使用する場合、スタックオーバーフローは問題になりません。実際、値は20です。は、Javaで表現できる最大のものです。したがって、次のメソッドは、nが大きすぎる場合、factorial(n)を計算するか、IllegalArgumentExceptionをスローします。
public long factorial(int n) {
if (n > 20) throw new IllegalArgumentException(n + " is out of range");
return (1 > n) ? 1 : n * factorial(n - 1);
}
同じことを行う別の(よりクールな)方法は、次のようにJava 8のストリームライブラリを使用することです。
public long factorial(int n) {
if (n > 20) throw new IllegalArgumentException(n + " is out of range");
return LongStream.rangeClosed(1, n).reduce(1, (a, b) -> a * b);
}
Java 8のストリームを使用したFactorialsの詳細を読む
短い答えは、再帰を使用することです。
1つのメソッドを作成し、そのメソッドを同じメソッド内で再帰的に呼び出すことができます。
public class factorial {
public static void main(String[] args) {
System.out.println(calc(10));
}
public static long calc(long n) {
if (n <= 1)
return 1;
else
return n * calc(n - 1);
}
}
System.out.println(calc(10));を試してみてください。System.out.println(calc(Long.MAX_VALUE));かなり長いstactraceが得られるはずです:)
BigInteger。小数点以下の桁数の8020結果613578884952214809325384...が得られた数値の階乗を計算しようとしました27831。したがって、そのような膨大な数を処理する場合でも、何Stackoverflowもスローされません。もちろんよろしいですが、実用的な使用でこれほど大きな数があるとは思いません:-)
これを試して
public static BigInteger factorial(int value){
if(value < 0){
throw new IllegalArgumentException("Value must be positive");
}
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= value; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
i <= value。forループは、にわずかに最適化できます(int i = 2; i <= value; i++)。
実際の乗算の半分で階乗を見つけるための素晴らしいトリックを見つけました。
これは少し長い記事ですので、しばらくお待ちください。
偶数の場合: 偶数で乗算を半分にするには、n / 2の係数になります。最初の要素は、階乗を取る数です。次の要素は、その数にその数を足したものから2を引いたものになります。次の数は、前の数に最後に追加された数から2を引いた数になります。最後に追加した番号が2(つまり2)になったときに完了です。それはおそらくあまり意味がなかったので、例を挙げましょう。
8! = 8 * (8 + 6 = 14) * (14 + 4 = 18) * (18 + 2 = 20)
8! = 8 * 14 * 18 * 20 which is **40320**
8から始め、最初に追加した数値は6、4、2の順になりました。追加された数値はそれぞれ、その前に追加された数値よりも2つ少なくなっています。この方法は、次のように、乗算を少なくして、最小数と最大数を乗算するのと同じです。
8! = 1 * 2 * 3 * 4 * 5 * 6 * 7 *
8! = (1 * 8) * (2 * 7) * (3 * 6) * (4 * 5)
8! = 8 * 14 * 18 * 20
シンプルじゃないですか:)
Now For Odd Numbers:数が奇数の場合、加算は同じです。毎回2を減算しますが、3で停止します。ただし、要素の数は変化します。数値を2で割ると、末尾が.5になる数値になります。その理由は、両端を掛け合わせると、中間の数が残されるためです。基本的に、これはすべて、数を2で割った数に等しい数の因子を切り上げて解決することで解決できます。これはおそらく、数学的な背景がない頭にもあまり意味がないので、例を挙げてみましょう。
9! = 9 * (9 + 7 = 16) * (16 + 5 = 21) * (21 + 3 = 24) * (roundUp(9/2) = 5)
9! = 9 * 16 * 21 * 24 * 5 = **362880**
注意:この方法が気に入らない場合は、奇数の前の偶数の階乗(この場合は8)を取り、奇数を乗算することもできます(つまり、9!= 8!* 9)。
それをJavaで実装しましょう:
public static int getFactorial(int num)
{
int factorial=1;
int diffrennceFromActualNum=0;
int previousSum=num;
if(num==0) //Returning 1 as factorial if number is 0
return 1;
if(num%2==0)// Checking if Number is odd or even
{
while(num-diffrennceFromActualNum>=2)
{
if(!isFirst)
{
previousSum=previousSum+(num-diffrennceFromActualNum);
}
isFirst=false;
factorial*=previousSum;
diffrennceFromActualNum+=2;
}
}
else // In Odd Case (Number * getFactorial(Number-1))
{
factorial=num*getFactorial(num-1);
}
return factorial;
}
isFirst静的として宣言されたブール変数です。以前の合計を変更したくない最初のケースに使用されます。
奇数だけでなく偶数でも試してください。
再帰を使用できます。
public static int factorial(int n){
if (n == 0)
return 1;
else
return(n * factorial(n-1));
}
上記のメソッド(関数)を作成した後:
System.out.println(factorial(number of your choice));
//direct example
System.out.println(factorial(3));
階乗を計算する非常に簡単な方法:
private double FACT(double n) {
double num = n;
double total = 1;
if(num != 0 | num != 1){
total = num;
}else if(num == 1 | num == 0){
total = 1;
}
double num2;
while(num > 1){
num2 = num - 1;
total = total * num2;
num = num - 1;
}
return total;
}
大量の数値を保持できるのでdoubleを使用しましたが、int、long、floatなど、他の任意の型を使用できます。
PSこれは最善の解決策ではないかもしれませんが、私はコーディングに慣れていないため、階乗を計算できる単純なコードを見つけるのに何年もかかりました。 。
階乗は非常に増加する離散関数なので、BigIntegerを使用する方がintを使用するよりも優れていると思います。非負の整数の階乗を計算するために次のコードを実装しました。ループを使用する代わりに再帰を使用しました。
public BigInteger factorial(BigInteger x){
if(x.compareTo(new BigInteger("1"))==0||x.compareTo(new BigInteger("0"))==0)
return new BigInteger("1");
else return x.multiply(factorial(x.subtract(new BigInteger("1"))));
}
ここで大きな整数の範囲は
-2^Integer.MAX_VALUE (exclusive) to +2^Integer.MAX_VALUE,
where Integer.MAX_VALUE=2^31.
ただし、上記の階乗法の範囲は、符号なしBigIntegerを使用して最大2倍に拡張できます。
それを計算するための単一の行があります:
Long factorialNumber = LongStream.rangeClosed(2, N).reduce(1, Math::multiplyExact);
かなり簡単な方法
for ( int i = 1; i < n ; i++ )
{
answer = answer * i;
}
/**
import java liberary class
*/
import java.util.Scanner;
/* class to find factorial of a number
*/
public class factorial
{
public static void main(String[] args)
{
// scanner method for read keayboard values
Scanner factor= new Scanner(System.in);
int n;
double total = 1;
double sum= 1;
System.out.println("\nPlease enter an integer: ");
n = factor.nextInt();
// evaluvate the integer is greater than zero and calculate factorial
if(n==0)
{
System.out.println(" Factorial of 0 is 1");
}
else if (n>0)
{
System.out.println("\nThe factorial of " + n + " is " );
System.out.print(n);
for(int i=1;i<n;i++)
{
do // do while loop for display each integer in the factorial
{
System.out.print("*"+(n-i) );
}
while ( n == 1);
total = total * i;
}
// calculate factorial
sum= total * n;
// display sum of factorial
System.out.println("\n\nThe "+ n +" Factorial is : "+" "+ sum);
}
// display invalid entry, if enter a value less than zero
else
{
System.out.println("\nInvalid entry!!");
}System.exit(0);
}
}
繰り返し実装する必要があります。再帰的に実装する場合、入力が非常に大きくなると(つまり20億)、StackOverflowが発生します。また、階乗数が特定の型の最大数(つまり、intで20億)より大きい場合に、算術オーバーフローを回避するために、BigIntegerなどのバインドされていないサイズ数を使用する必要があります。オーバーフローの前に、最大14の階乗に対してintを、最大20の階乗に対してlongを使用できます。
public BigInteger getFactorialIteratively(BigInteger input) {
if (input.compareTo(BigInteger.ZERO) <= 0) {
throw new IllegalArgumentException("zero or negatives are not allowed");
}
BigInteger result = BigInteger.ONE;
for (BigInteger i = BigInteger.ONE; i.compareTo(input) <= 0; i = i.add(BigInteger.ONE)) {
result = result.multiply(i);
}
return result;
}
BigIntegerを使用できない場合は、エラーチェックを追加します。
public long getFactorialIteratively(long input) {
if (input <= 0) {
throw new IllegalArgumentException("zero or negatives are not allowed");
} else if (input == 1) {
return 1;
}
long prev = 1;
long result = 0;
for (long i = 2; i <= input; i++) {
result = prev * i;
if (result / prev != i) { // check if result holds the definition of factorial
// arithmatic overflow, error out
throw new RuntimeException("value "+i+" is too big to calculate a factorial, prev:"+prev+", current:"+result);
}
prev = result;
}
return result;
}
public int factorial(int num) {
if (num == 1) return 1;
return num * factorial(num - 1);
}
再帰あり:
public static int factorial(int n)
{
if(n == 1)
{
return 1;
}
return n * factorial(n-1);
}
whileループ:
public static int factorial1(int n)
{
int fact=1;
while(n>=1)
{
fact=fact*n;
n--;
}
return fact;
}
動的プログラミングの使用は効率的です
繰り返し計算するためにそれを使用したい場合(キャッシュのように)
Javaコード:
int fact[]=new int[n+1]; //n is the required number you want to find factorial for.
int factorial(int num)
{
if(num==0){
fact[num]=1;
return fact[num];
}
else
fact[num]=(num)*factorial(num-1);
return fact[num];
}
再帰を使用するのが最も簡単な方法です。Nの階乗を求める場合は、N = 1とN> 1の2つのケースを考慮する必要があります。階乗では、N、N-1、N-2 ,,,,を1まで乗算し続けるためです。 N = 0に行くと、答えは0になります。階乗がゼロに達するのを防ぐために、次の再帰的方法が使用されます。階乗関数内では、N> 1の間、戻り値は階乗関数の別の開始と乗算されます。これは、N = 1に到達するまで、コードがfactorial()を再帰的に呼び出し続けます。N= 1の場合、N(= 1)自体を返し、以前に作成された乗算結果N sのすべての以前に作成された結果にNが乗算されます。 = 1。したがって、階乗の結果が得られます。
static int factorial(int N) {
if(N > 1) {
return n * factorial(N - 1);
}
// Base Case N = 1
else {
return N;
}