Factorial in Java

我一直在使用这个Java的阶乘程序:

public static long factorial(int a) { if(a1) { result*=x; x--; } return result; } 

然而,它似乎“破裂”并在25的阶乘后返回一个负数。它返回一个负数然后只返回“0”。

我做错了导致这种情况吗?

你已经满溢了。
请改用BigInteger

25! = 15511210043330985984000000

Java中long的最大值是2^63-1 = 9223372036854775807 ( 源 )。

25! 大约是1.7 * 10 ^ 6大小的长度可以存储在Java中。 请改用BigInteger

25! 大于Long.MAX_VALUE

根据JLS,溢出(和下溢)是静默的,这就是为什么你的结果是“惊喜”。

你有两个选择:

  • 如果需要确切答案,请使用BigInteger
  • 如果不需要精确度,请使用double (尽管即使超过170!也会溢出170!

另一种不那么天真且适用于非整数的方法是使用伽玛函数的自然对数。

http://www.iro.umontreal.ca/~simardr/ssj/doc/html/umontreal/iro/lecuyer/util/Num.html

如果您必须坚持使用此实现,我建议您查看memoization。 为什么要重新计算价值? 一旦你有一个,挂在它上面,然后重复请求。

查看http://en.wikipedia.org/wiki/Integer_overflow ,我知道标题是指一个整数,但原理代表int,long,double等。

简而言之,原始数据类型具有最大值,当您重新执行该操作时,它会包含aroun并再次启动。 如果你真的想要了解它,请学习二进制加法以完全理解它。

这就是你所缺少的:当有符号整数基元类型(例如short,int,long)增加到它可以表示的有符号值之上时,它会尝试翻转其符号位,这是最左边的位,这只是应该用来表示号码的标志。 符号位中的1表示负值。 这种现象称为整数溢出。

考虑一个虚构的3位有符号原始数据类型(为了比较,Java long是64位)。 它可以表示-4到3之间的数字。

3,3位数可以表示的最大正值,如下所示:011

添加1到011,你得到:100(数字部分溢出到标志部分)

100的十进制版本是-4

但是,当你处理long的容量时,需要计算很多位数,所以这里有一个快速的方法来确定给定的非递减序列(在这种情况下,factorial)定义的最大数字:

 long n = 1; while (factorial(n) > 0) { System.out.println("factorial of " + n++ + " can fit in a long!"); } 

这看起来应该是一个无限循环,但它不是; 最终,factorial(n)将因整数溢出而返回负数。 这将为您提供以下输出:

 factorial of 1 can fit in a long! factorial of 2 can fit in a long! factorial of 3 can fit in a long! factorial of 4 can fit in a long! factorial of 5 can fit in a long! factorial of 6 can fit in a long! factorial of 7 can fit in a long! factorial of 8 can fit in a long! factorial of 9 can fit in a long! factorial of 10 can fit in a long! factorial of 11 can fit in a long! factorial of 12 can fit in a long! factorial of 13 can fit in a long! factorial of 14 can fit in a long! factorial of 15 can fit in a long! factorial of 16 can fit in a long! factorial of 17 can fit in a long! factorial of 18 can fit in a long! factorial of 19 can fit in a long! factorial of 20 can fit in a long!