【问题标题】:When calculating the factorial of 100 (100!) with Java using integers I get 0当使用 Java 使用整数计算 100(100!)的阶乘时,我得到 0
【发布时间】:2011-07-16 02:54:01
【问题描述】:

当这样做时:

int x = 100;
int result = 1;
for (int i = 1; i < (x + 1); i++) {
    result = (result * i);
}
System.out.println(result);

这显然是因为结果对于整数来说太大了,但我习惯于为溢出得到大的负数,而不是 0。

提前致谢!


当我切换到这个时:

int x = 100;
int result = 1;

for (int i = 1; i < (x + 1); i++) {
    result = (result * i);
    System.out.println(result);
}

我收到this

【问题讨论】:

  • 这不是计算阶乘的最佳方法。你知道的,对吧?
  • 即使你不会得到 0,你的循环也不会计算阶乘。
  • @duffymo:是的,我只是对输出感到好奇。谢谢!
  • @Roflcoptr:我认为确实如此,我刚刚测试了 9 次,结果正确。
  • @duffymo 当然!毕竟,如果我想要5!,我不会做5*4*3*2*1。我要评估gamma(6)

标签: java overflow int factorial


【解决方案1】:

大负数是溢出到特定范围内的值; factorial(100) 末尾有超过 32 个二进制零,因此将其转换为整数会产生零。

【讨论】:

    【解决方案2】:

    肯定是溢出了,你可以试试double,64位长整数可能太小了

    【讨论】:

    • 是的,有 - 快速计数显示超过 75 个零,这超过了 long 中的 64 位。
    • 您好,谢谢!这应该是评论,而不是答案,不,对于 100 它仍然太小,唯一的方法是使用 BigInteger
    • @Trufa:如果你只需要大概的结果,你可以使用double——它会比 BigInteger 快得多。
    【解决方案3】:

    很好的问题 - 答案是: 33 的阶乘(由于负值)是 -2147483648,即 0x80000000,如果采用 64 位,则为 0xFFFFFFFF80000000。乘以 34(下一个成员)将得到 0xFFFFFFE600000000 的 long 值,当转换为 int 时会得到 0x00000000

    显然,从那时起,您将保持 0。

    【讨论】:

      【解决方案4】:

      1 到 100 之间有 50 个偶数。这意味着阶乘是 2 的倍数至少 50 倍,换句话说,作为二进制数,最后 50 位将为 0。(实际上它更多,因为偶数第二个偶数是 2*2 的倍数等)

      public static void main(String... args) {
          BigInteger fact = fact(100);
          System.out.println("fact(100) = " + fact);
          System.out.println("fact(100).longValue() = " + fact.longValue());
          System.out.println("fact(100).intValue() = " + fact.intValue());
          int powerOfTwoCount = 0;
          BigInteger two = BigInteger.valueOf(2);
          while (fact.compareTo(BigInteger.ZERO) > 0 && fact.mod(two).equals(BigInteger.ZERO)) {
              powerOfTwoCount++;
              fact = fact.divide(two);
          }
          System.out.println("fact(100) powers of two = " + powerOfTwoCount);
      }
      
      private static BigInteger fact(long n) {
          BigInteger result = BigInteger.ONE;
          for (long i = 2; i <= n; i++)
              result = result.multiply(BigInteger.valueOf(i));
          return result;
      }
      

      打印

      fact(100) = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
      fact(100).longValue() = 0
      fact(100).intValue() = 0
      fact(100) powers of two = 97
      

      这意味着 97 位整数对于 fact(100) 的最低位将为 0

      事实上,对于 fact(n),2 的幂数非常接近 n。事实上(10000)有 9995 次方 2。这是因为它大约是 1/2 的 n 次幂的总和,总和接近 n。即,每第二个数字是偶数 n/2,每 4 个有一个额外的 2 幂(+n/4),每 8 个有一个额外的幂(+n/8)等接近 n 作为总和。

      【讨论】:

      • @Trufa:试试这个程序,在每一步之后打印(BigIntegerint)结果,以获得更多洞察力。
      • @PaloEbermann:我做到了,我实际上能够解决这个问题,但对 0 结果很好奇。谢谢!
      • 希望我已经解释了为什么你会在答案的末尾得到这么多 0 位,这就是你在做一个大的阶乘时剩下的全部。事实上 fib(34).intValue() == 0
      • @PeterLawrey:我已经理解了你的大部分答案,我还在编辑中,我的数学也不会太快(但它来了......):)
      • @RonK,感谢您发现这一点,在我看到您的评论之前对其进行了更改。 fib 应该是斐波那契的缩写。 fact 是阶乘的更好简称。这些斐波那契/阶乘答案已经写了太多次了。 ;)
      【解决方案5】:

      要查看原因,我们可以观察阶乘的素因数分解。

      fac( 1) = 1             = 2^0
      fac( 2) = 2             = 2^1
      fac( 3) = 2 * 3         = 2^1 * 3
      fac( 4) = 2 * 2 * 2 * 3 = 2^3 * 3
      fac( 5) =  ...          = 2^3 * 3 * 5
      fac( 6) = ...           = 2^4 * 3^2 * 5
      fac( 7) = ...           = 2^4 * ...
      fac( 8) = ...           = 2^7 * ...
      fac( 9) = ...           = 2^7 * ...
      fac(10) = ...           = 2^8 * ...
      fac(11) = ...           = 2^8 * ...
      ...
      fac(29) = ...           = 2^25 * ...
      fac(30) = ...           = 2^26 * ...
      fac(31) = ...           = 2^26 * ...
      fac(32) = ...           = 2^31 * ...
      fac(33) = ...           = 2^31 * ...
      fac(34) = ...           = 2^32 * ...  <===
      fac(35) = ...           = 2^32 * ...
      fac(36) = ...           = 2^34 * ...
      ...
      fac(95) = ...           = 2^88 * ...
      fac(96) = ...           = 2^93 * ...
      fac(97) = ...           = 2^93 * ...
      fac(98) = ...           = 2^94 * ...
      fac(99) = ...           = 2^94 * ...
      fac(100)= ...           = 2^96 * ...
      

      2 的指数是基数为 2 的视图中尾随零的数量,因为所有其他因素都是奇数,因此在乘积的最后一个二进制数字中贡献了 1

      类似的方案也适用于其他素数,因此我们可以轻松计算 fac(100) 的因式分解:

      fac(100) = 2^96 * 3^48 * 5^24 * 7^16 * 11^9 * 13^7 * 17^5 * 19^5 * 23^4 *
                 29^3 * 31^2 * 37^2 * 41^2 * 43^2 * 47^2 *
                 53 * 59 * 61 * 67 * 71 * 73 * 79 * 83 * 89 * 97
      

      因此,如果我们的计算机以 3 为基数存储数字,并且有 48 个三位数字,则fac(100) 将是 0(与 fac(99) 一样,但 fac(98) 不会:-)

      【讨论】:

        【解决方案6】:

        (找到here稍微适应问题)

        public static void main(String[] args) {
        
            BigInteger fact = BigInteger.valueOf(1);
            for (int i = 1; i <= 100; i++)
                fact = fact.multiply(BigInteger.valueOf(i));
            System.out.println(fact);
        }
        

        【讨论】:

          【解决方案7】:

          使用递归和 BigIntegers 的简单解决方案:

              public static BigInteger factorial(int num){
              if (num<=1)
                  return BigInteger.ONE;
              else
                  return factorial(num-1).multiply(BigInteger.valueOf(num));
              }
          

          输出:

          93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
          

          【讨论】:

            【解决方案8】:

            Java 中的 BigInteger 类。 BigInteger 类用于涉及非常大的整数计算的数学运算,超出了所有可用原始数据类型的限制。

            要计算非常大的数字,我们可以使用 BigInteger

            比如,如果我们要计算 45 的阶乘, 答案 = 119622220865480194561963161495657715064383733760000000000

             static void extraLongFactorials(int n) {
                   BigInteger fact = BigInteger.ONE;
                    for(int i=2; i<=n; i++){
                        fact = fact.multiply(BigInteger.valueOf(i));
                    }
                    System.out.println(fact);
                }
            

            BigInteger的主要方法有BigInteger.ONE、BigInteger.ZERO、BigInteger.TEN、BigInteger.ValueOf()

            【讨论】:

              【解决方案9】:
              import java.util.*;
              import java.math.*;
              public class BigInteger_Factorial {
                  public static void main(String args []){
                      Scanner s = new Scanner(System.in);
              
                      BigInteger x,i,fac = new BigInteger("1");
                      x = s.nextBigInteger();
              
                      for(i=new BigInteger("1"); i.compareTo(x)<=0; i=i.add(BigInteger.ONE)){
                          fac = fac.multiply((i));
                      }
                      System.out.println(fac);
                  }
              }
              

              输出 100 作为输入:

              93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
              

              输出图像:

              【讨论】:

                【解决方案10】:
                package test2;
                
                import java.math.BigInteger;
                import java.util.Scanner;
                
                public class Factorial extends Big {
                
                    public static void main(String args []){ 
                    int x,fact=1,i ;
                    Scanner sc = new Scanner(System.in);
                    
                    
                    System.out.println("press any dight and 0 to exit");
                    while (sc.nextInt()!=0)
                    {
                    System.out.println("Enter the values ");
                    x=sc.nextInt();
                    if(x<26)
                
                    {
                    for( i=1;i<=x;i++)
                    {   fact = fact*i;  }
                    
                    System.out.println("Factorial of "+x + "is "+ fact );
                    
                    fact=1;
                    }
                    else 
                    {
                        System.out.println("In else big....");
                    BigInteger k=fact(x);
                    
                    System.out.println("The factorial of "+x+"is "+k);
                    System.out.println("RESULT LENGTH\n"+k.toString().length());
                    }
                    System.out.println("press any dight and 0 to exit");
                    }
                    System.out.println("thanks....");
                    }
                    
                        
                    
                    
                }
                //----------------------------------------------------//
                
                package test2;
                
                import java.math.BigInteger;
                
                public class Big {
                
                    public static void main(String... args) {
                        BigInteger fact = fact(100);
                        System.out.println("fact(100) = " + fact);
                        System.out.println("fact(100).longValue() = " + fact.longValue());
                        System.out.println("fact(100).intValue() = " + fact.intValue());
                        int powerOfTwoCount = 0;
                        BigInteger two = BigInteger.valueOf(2);
                        while (fact.compareTo(BigInteger.ZERO) > 0 && fact.mod(two).equals(BigInteger.ZERO)) {
                            powerOfTwoCount++;
                            fact = fact.divide(two);
                        }
                        System.out.println("fact(100) powers of two = " + powerOfTwoCount);
                    }
                
                    public static BigInteger fact(long n) {
                        BigInteger result = BigInteger.ONE;
                        for (long i = 2; i <= n; i++)
                            result = result.multiply(BigInteger.valueOf(i));
                        return result;
                    }
                    
                }   
                

                【讨论】:

                • 这里我从 Big 扩展了这个类
                • 和最大值 2450
                • 它给出了无限的阶乘程序,但最好的结果显示在 2450 并且还取决于硬件,,System.out.println("RESULT LENGTH\n"+k.toString().length() );正在显示结果集长度
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-02-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-07-03
                相关资源
                最近更新 更多