有没有一种方法可以计算Java中的阶乘?

时间:2009-05-21 01:31:34

标签: java

我还没找到它。我错过了什么? 我知道一个阶乘方法是初学者的常见示例程序。但是,重新使用这个标准实现是不是很有用? 我可以使用标准类型(int,long ...)和BigInteger / BigDecimal这样的方法。

31 个答案:

答案 0 :(得分:53)

Apache Commons MathMathUtils类中有一些因子方法。

答案 1 :(得分:39)

public class UsefulMethods {
    public static long factorial(int number) {
        long result = 1;

        for (int factor = 2; factor <= number; factor++) {
            result *= factor;
        }

        return result;
    }
}

HoldOffHunger的大数字版本:

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

答案 2 :(得分:25)

我认为为factorial提供库函数不会有用。对有效的因子实现进行了大量研究。 Here is a handful of implementations.

答案 3 :(得分:22)

在实践中很少需要赤裸裸的阶乘。大多数情况下,您需要以下其中一项:

1)将一个阶乘除以另一个阶乘,或

2)近似浮点答案。

在这两种情况下,您都可以使用简单的自定义解决方案。

在情况(1)中,例如,如果x = 90! / 85!,然后你将计算结果就像x = 86 * 87 * 88 * 89 * 90,而不需要保持90!在记忆中:)

在案例(2)中,谷歌搜索“斯特林的近似值”。

答案 4 :(得分:11)

使用Guava的BigIntegerMath如下:

BigInteger factorial = BigIntegerMath.factorial(n);

intlong的类似功能分别在IntMathLongMath中提供。)

答案 5 :(得分:6)

因为factorial增长如此之快,如果使用递归,堆栈溢出不是问题。其实价值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);
}

详细了解Factorials using Java 8's streams

答案 6 :(得分:6)

我相信这将是最快的方式,通过查找表:

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!,有意义且正确。

答案 7 :(得分:6)

简短回答是:使用递归。

您可以创建一个方法并在递归的同一方法内调用该方法:

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

答案 8 :(得分:6)

Apache Commons Math包有a factorial method,我想你可以使用它。

答案 9 :(得分:5)

虽然阶乘为初级程序员做了很好的练习,但在大多数情况下它们并不是很有用,并且每个人都知道如何编写阶乘函数,所以它们通常不是平均值库。

答案 10 :(得分:3)

试试这个

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

答案 11 :(得分:2)

You can use recursion.

data.frame

and then after you create the method(function) above:

   levels_together group_by_var kernel_type
1             0.051      tw     b
2             0.055      tw     b
3             0.053      fif    b
4             0.046      fif    b
5             0.053      sev    b
6             0.050      sev    b
7             0.059      tw     e
8             0.056      tw     e
9             0.052      fif    e
10            0.044      fif    e
11            0.058      sev    e
12            0.053      sev    e
13            0.052      tw     p
14            0.053      tw     p
15            0.051      fif    p
16            0.044      fif    p
17            0.051      sev    p
18            0.050      sev    p

答案 12 :(得分:2)

我找到了一个惊人的技巧,可以在实际乘法的一半中找到阶乘。

请耐心等待,因为这是一个很长的帖子。

对于偶数: 要将偶数乘以一半,最终会得到n / 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,每个数字加上比之前添加的数字少两个。此方法相当于将最小数字乘以最大数字,只需乘以较少的乘法,如下所示:

8! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 
8! = (1 * 8) * (2 * 7) * (3 * 6) * (4 * 5)
8! = 8 * 14 * 18 * 20

简单不是:)

现在对于奇数:如果数字是奇数,则添加是相同的,就像每次减去两个,但是你停在三。然而,因素的数量会发生变化。如果将数字除以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是一个声明为static的布尔变量;它用于我们不想改变之前总和的第一种情况。

尝试使用偶数和奇数。

答案 13 :(得分:1)

我能想到的唯一商业用途是Erlang B和Erlang C公式,并不是每个人都在呼叫中心或电话公司工作。功能对业务的有用性似乎经常决定了语言中出现的内容 - 查看主要语言中的所有数据处理,XML和Web功能。

很容易为这样的事情保留一个因子片段或库函数。

答案 14 :(得分:1)

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

答案 15 :(得分:1)

一种相当简单的方法

    for ( int i = 1; i < n ; i++ )
    {
            answer = answer * i;
    }

答案 16 :(得分:1)

我们只用一行来计算它:

Long factorialNumber = LongStream.rangeClosed(2, N).reduce(1, Math::multiplyExact);

答案 17 :(得分:1)

因子是高度增加的离散函数。所以我认为使用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,上面给出的阶乘方法的范围可以扩展到两倍。

答案 18 :(得分:1)

您也可以使用递归版本。

static int myFactorial(int i) {
    if(i == 1)
        return;
    else
        System.out.prinln(i * (myFactorial(--i)));
}

递归通常效率较低,因为必须推送和弹出递归,因此迭代更快。另一方面,递归版本使用较少或没有局部变量,这是有利的。

答案 19 :(得分:1)

计算阶乘的一种非常简单的方法:

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等。

P.S。这可能不是最好的解决方案,但我是编码的新手,我花了很长时间才找到一个可以计算阶乘的简单代码,所以我必须自己写这个方法,但是我把它放在这里,所以它有助于像我这样的其他人。

答案 20 :(得分:0)


public static long factorial(int number) {
    if (number < 0) {
        throw new ArithmeticException(number + " is negative");
    }
    long fact = 1;
    for (int i = 1; i <= number; ++i) {
        fact *= i;
    }
    return fact;
}

使用递归。


public static long factorial(int number) {
    if (number < 0) {
        throw new ArithmeticException(number + " is negative");
    }
    return number == 0 || number == 1 ? 1 : number * factorial(number - 1);
}

source

答案 21 :(得分:0)

使用递归是最简单的方法。如果我们想找到的阶乘 N,由于阶乘,我们必须考虑N = 1和N> 1的两种情况 我们继续乘以N,N-1,N-2 ,,,,,直到1。如果我们转到N = 0,我们将得到0 寻找答案。为了阻止阶乘达到零,以下 使用递归方法。在阶乘函数内部,当N> 1时,返回 值乘以阶乘函数的另一个启动。这个 将保持代码递归调用factorial()直到到达 N = 1.对于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;
    }

答案 22 :(得分:0)

使用动态编程很有效

如果要使用它一次又一次地计算(例如缓存)

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

答案 23 :(得分:0)

使用 Java 9+,您可以使用此解决方案。这使用 BigInteger,非常适合保存大数。

...    
import java.math.BigInteger;
import java.util.stream.Stream;
...

String getFactorial(int n) {
    return Stream.iterate(BigInteger.ONE, i -> i.add(BigInteger.ONE)).parallel() 
            .limit(n).reduce(BigInteger.ONE, BigInteger::multiply).toString();
}

答案 24 :(得分:0)

只是为了好玩: 与FileNotFoundError: [Errno 2] No such file or directory: 'cmake': 'cmake'一起使用的单线析因方法:

BigInteger

答案 25 :(得分:0)

带递归:

public static int factorial(int n)
{
    if(n == 1)
    {
        return 1;
    }               
    return n * factorial(n-1);
}

with while循环:

public static int factorial1(int n)
{
    int fact=1;
    while(n>=1)
    {
        fact=fact*n;
        n--;
    }
    return fact;
}

答案 26 :(得分:0)

我从EDX那里得到了它!它叫做递归

   public static int factorial(int n) {
    if (n == 1) {
        return 1;
    } else {
        return n * factorial(n-1);
    }
}

答案 27 :(得分:0)

while循环(对于小数字)

public class factorial {

public static void main(String[] args) {
    int counter=1, sum=1;

    while (counter<=10) {
        sum=sum*counter;
        counter++;
   }

    System.out.println("Factorial of 10 is " +sum);
   }
}

答案 28 :(得分:0)

public int factorial(int num) {
        if (num == 1) return 1;
        return num * factorial(num - 1);
}

答案 29 :(得分:0)

我们需要迭代实现。如果我们以递归方式实现,如果输入变得非常大(即20亿),它将导致StackOverflow。我们需要使用未绑定的大小数字,例如BigInteger,以避免当因子数大于给定类型的最大数(即int为20亿)时的算术溢出。您可以使用int最多14个阶乘,最长20个 溢出之前的阶乘。

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

答案 30 :(得分:0)

public static int fact(int i){
    if(i==0)
       return 0;
    if(i>1){
       i = i * fact(--i);
    }

   return i;
}