【问题标题】:Is there a method that calculates a factorial in Java? [closed]有没有一种方法可以在 Java 中计算阶乘? [关闭]
【发布时间】:2009-05-21 01:31:33
【问题描述】:

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

【问题讨论】:

    标签: java


    【解决方案1】:

    Apache Commons MathMathUtils 类中有一些阶乘方法。

    【讨论】:

    • 是的。好东西。有一个浮点数和非平面数的阶乘实现(MathUtils.factorial(int) 和 MathUtils.factorialDouble(int)),还有有用的 n 的自然对数! (MathUtils.factorialLog(int))
    • 目前在 ArithmeticUtils 中。
    • ArithmeticUtils.factorial 现在似乎已弃用,atm 使用CombinatoricsUtils.factorial
    • 请不要使用链接!它们往往会消失(就像所有这些一样)。
    • @ScottBiggs 答案中的两个链接都工作正常。
    【解决方案2】:
    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;
    }
    

    【讨论】:

    • 另外你假设你想要一个整数的阶乘
    • 这个解决方案应该使用 BigInteger 类。
    • Big Numbers 版本:public static BigInteger factorial(BigInteger n) { BigInteger factorial = BigInteger.valueOf(1); for (int i = 1; i
    【解决方案3】:

    我不认为有一个库函数用于阶乘。对有效的阶乘实现进行了大量研究。 Here is a handful of implementations.

    【讨论】:

    • 为什么对于阶乘没有库函数?
    • 在实际代码中真正需要阶乘的人并不多。如果你这样做了,那么你可能正在做一些高级数学或统计,在这种情况下,你很可能已经在使用具有专门的阶乘实现的数学库。
    • gamma 函数非常有用,这就是它被包含在 C++ 标准库中的原因。
    • 在我看来,@KarlthePagan 意味着为阶乘拥有 标准 库函数没有用——对吗?
    • 所以他们会在面试时问你是否可以自己做 *my case
    【解决方案4】:

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

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

    2) 近似浮点答案。

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

    在情况 (1) 中,假设 x = 90! / 85!,那么你将计算结果就像 x = 86 * 87 * 88 * 89 * 90,而不需要保持 90!在内存中:)

    在情况(2)中,谷歌搜索“斯特林近似”。

    【讨论】:

    • 反例:计算具有 N 个元素的排列数需要纯阶乘,如果您想分配一个结构来保存排列,则需要。
    • 好点!我的第一个问题是如果 90!/85!因为公分母是 5 而简化了,但实际上,它是公分母 85!。 90!/85! = 90*89*88*87*86​​85!/85!。你可以在那个平等中更清楚地看到它。
    【解决方案5】:

    使用Guava的BigIntegerMath如下:

    BigInteger factorial = BigIntegerMath.factorial(n);
    

    intlong 的类似功能分别在 IntMathLongMath 中可用。)

    【讨论】:

      【解决方案6】:

      虽然阶乘对于初学者来说是一个很好的练习,但在大多数情况下它们并不是很有用,而且每个人都知道如何编写阶乘函数,所以它们通常不是一般的图书馆。

      【讨论】:

      • 我同意你的观点,还有更重要的数学函数。但在我看来,这种方法应该是标准的,以便人们可以重复使用它。无需多人多次实施。出于教育目的,他们可能会这样做。但是对于每天的工作来说,它已经过时了。这是我的意见。无论如何,谢谢你的回答。我会自己做的——下次再做。
      • 您提议的标准化有什么好处?向标准库添加方法并非没有成本。正如其他人所指出的,没有单一的最佳 解决方案。您建议将哪一个构建到语言中?在标准库中拥有一个方法并不能节省您理解问题的时间,一旦您这样做了,您不妨选择最适合该工作的实现。
      • "...大家都知道怎么写阶乘函数"chaosinmotion.com/blog/?p=622
      • 不同意。 Combinatorics 需要阶乘,这在软件设计的许多领域都是必需的。在内置数学库中不包含阶乘的参数与没有内置数学库的参数相同。
      • 多么出色的逻辑。绝对一流。太糟糕了,当 java.lang.Math 类设计者将 abs() 方法包含到该库中时,他们对此一无所知。
      【解决方案7】:

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

      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 个阶乘可能就足够了,我会使用提供的这些数据向 Math 类添加一个静态常量(无需每次启动应用程序时都计算它)。事实上,在他们的代码中没有多少人需要阶乘,这是在数学课中不支持它的一个糟糕的借口。
      【解决方案8】:

      因为阶乘增长如此之快,如果使用递归,堆栈溢出不是问题。其实值20!是 Java long 中可以表示的最大长度。因此,如果 n 太大,以下方法将计算阶乘(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

      【讨论】:

        【解决方案9】:

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

        【讨论】:

        • 更新后的链接是this
        • @Krige 刚刚修复了链接
        【解决方案10】:

        简短的回答是:使用递归。

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

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

        【讨论】:

        • 递归函数很好,但是如果有人尝试计算一个非常大的错误,他们最终会得到 StackOverflowException ;) + 我不确定,但我认为递归比旧的循环方法慢;)
        • 你怎么知道它会以stackoverflow异常结束? @TG
        • 这很简单。每个递归都将当前位置放在堆栈上,因此程序将在方法调用完成后返回“内存”位置。堆栈有其局限性。自己尝试一下,在上面的代码中尝试将System.out.println(calc(10)); 更改为System.out.println(calc(Long.MAX_VALUE));,你应该得到相当长的 stactrace :)
        • @TG 要清楚,我试过my recursive methodBigInteger 一起工作。我试图计算数字8020 的阶乘,结果613578884952214809325384...27831 小数位。因此,即使在处理大量没有Stackoverflow 的数字时也会被抛出。当然你是对的,但我怀疑有实际用途的大数字:-)
        【解决方案11】:

        试试这个

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

        【讨论】:

        • 我相信for循环中有一个错误:它应该是i &lt;= value。 for 循环可以稍微优化为(int i = 2; i &lt;= value; i++)
        【解决方案12】:

        你可以使用递归。

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

        【讨论】:

          【解决方案13】:

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

          这篇文章有点长,请耐心等待。

          偶数: 要将偶数乘法减半,您将得到 n/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
          

          简单是不是:)

          现在对于奇数:如果数字是奇数,则加法是相同的,例如每次减去 2,但在 3 处停止。然而,因素的数量发生了变化。如果你将这个数字除以 2,你最终会得到一些以 0.5 结尾的数字。原因是,如果我们将两端相乘,剩下的就是中间的数字。基本上,这都可以通过求解等于数字除以二的多个因子来解决,四舍五入。对于没有数学背景的人来说,这可能没有多大意义,所以让我举个例子:

          9! = 9 * (9 + 7 = 16) * (16 + 5 = 21) * (21 + 3 = 24) * (roundUp(9/2) = 5)
          
          9! = 9 * 16 * 21 * 24 * 5 = **362880**
          

          注意:如果你不喜欢这种方法,你也可以在奇数之前取偶数的阶乘(在这种情况下是八),然后乘以奇数(即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 是一个声明为静态的布尔变量;它用于第一种情况,我们不想更改之前的总和。

          尝试偶数和奇数。

          【讨论】:

            【解决方案14】:

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

            为类似的事情保留阶乘 sn-p 或库函数很容易。

            【讨论】:

              【解决方案15】:

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

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

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

              【讨论】:

                【解决方案16】:

                你也可以使用递归版本。

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

                由于必须推送和弹出递归,递归通常效率较低,因此迭代更快。另一方面,递归版本使用较少或不使用局部变量,这是一个优势。

                【讨论】:

                  【解决方案17】:

                  我们需要迭代地实现。如果我们递归实现,如果输入变得非常大(即 20 亿),它将导致 StackOverflow。当阶乘数变得大于给定类型的最大数(即 int 为 20 亿)时,我们需要使用诸如 BigInteger 之类的未绑定大小数来避免算术溢出。您可以将 int 用于最多 14 的阶乘,使用 long 用于最多 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;
                  }
                  

                  【讨论】:

                    【解决方案18】:

                    Factorial 是高度递增的离散函数。所以我认为使用 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.
                    

                    但是,上面给出的阶乘方法的范围可以通过使用 unsigned BigInteger 扩展到两倍。

                    【讨论】:

                      【解决方案19】:

                      我们只有一行来计算它:

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

                      【讨论】:

                        【解决方案20】:

                        一个相当简单的方法

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

                        【讨论】:

                          【解决方案21】:
                              /**
                          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);
                          }
                          }
                          

                          【讨论】:

                            【解决方案22】:
                            public static int fact(int i){
                                if(i==0)
                                   return 0;
                                if(i>1){
                                   i = i * fact(--i);
                                }
                            
                               return i;
                            }
                            

                            【讨论】:

                            • 我认为 OP 是在询问 API 中是否有函数,而不是如何编写函数。还有,0! = 1 - 您可能希望更新您的代码以包含该案例。
                            【解决方案23】:
                            public int factorial(int num) {
                                    if (num == 1) return 1;
                                    return num * factorial(num - 1);
                            }
                            

                            【讨论】:

                            • 应该使用 long 或 BigInteger ;)
                            【解决方案24】:

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

                            【讨论】:

                              【解决方案25】:

                              我从 EDX 得到这个,用它!它称为递归

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

                              【讨论】:

                                【解决方案26】:

                                使用递归:

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

                                【讨论】:

                                  【解决方案27】:

                                  使用递归是最简单的方法。如果我们想找到的阶乘 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;
                                      }
                                  

                                  【讨论】:

                                    【解决方案28】:
                                    
                                    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

                                    【讨论】:

                                      【解决方案29】:

                                      使用 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();
                                      }
                                      

                                      【讨论】:

                                        【解决方案30】:

                                        使用动态编程是有效的

                                        如果你想用它来一次又一次地计算(比如缓存)

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

                                        【讨论】:

                                        • 使用没有递归的动态规划更好。
                                        猜你喜欢
                                        • 1970-01-01
                                        • 2021-12-13
                                        • 1970-01-01
                                        • 2012-04-09
                                        • 2011-08-29
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2013-01-21
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多