【发布时间】:2009-05-21 01:31:33
【问题描述】:
我还没找到。我错过了什么? 我知道阶乘法是初学者的常见示例程序。但是,有一个标准的实现让这个实现重用不是很有用吗? 我可以将这种方法用于标准类型(例如 int、long...)以及 BigInteger / BigDecimal。
【问题讨论】:
标签: java
我还没找到。我错过了什么? 我知道阶乘法是初学者的常见示例程序。但是,有一个标准的实现让这个实现重用不是很有用吗? 我可以将这种方法用于标准类型(例如 int、long...)以及 BigInteger / BigDecimal。
【问题讨论】:
标签: java
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 的大数字版:
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;
}
【讨论】:
我不认为有一个库函数用于阶乘。对有效的阶乘实现进行了大量研究。 Here is a handful of implementations.
【讨论】:
在实践中很少需要赤裸裸的阶乘。大多数情况下,您需要以下其中一项:
1) 将一个阶乘除以另一个,或
2) 近似浮点答案。
在这两种情况下,您最好使用简单的自定义解决方案。
在情况 (1) 中,假设 x = 90! / 85!,那么你将计算结果就像 x = 86 * 87 * 88 * 89 * 90,而不需要保持 90!在内存中:)
在情况(2)中,谷歌搜索“斯特林近似”。
【讨论】:
使用Guava的BigIntegerMath如下:
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 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);
}
【讨论】:
Apache Commons Math 包有 a factorial method,我想你可以使用它。
【讨论】:
简短的回答是:使用递归。
您可以创建一个方法并在同一方法中递归地调用该方法:
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++)。
你可以使用递归。
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));
【讨论】:
我发现了一个惊人的技巧,可以在实际乘法的一半中找到阶乘。
这篇文章有点长,请耐心等待。
偶数: 要将偶数乘法减半,您将得到 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 是一个声明为静态的布尔变量;它用于第一种情况,我们不想更改之前的总和。
尝试偶数和奇数。
【讨论】:
我能想到的阶乘的唯一商业用途是 Erlang B 和 Erlang C 公式,并不是每个人都在呼叫中心或电话公司工作。一项功能对业务的有用性似乎通常决定了一种语言中显示的内容 - 查看主要语言中的所有数据处理、XML 和 Web 功能。
为类似的事情保留阶乘 sn-p 或库函数很容易。
【讨论】:
一种非常简单的阶乘计算方法:
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 等。
附:这可能不是最好的解决方案,但我是编码新手,我花了很长时间才找到一个可以计算阶乘的简单代码,所以我不得不自己编写这个方法,但我把它放在这里是为了帮助像我这样的其他人。
【讨论】:
你也可以使用递归版本。
static int myFactorial(int i) {
if(i == 1)
return;
else
System.out.prinln(i * (myFactorial(--i)));
}
由于必须推送和弹出递归,递归通常效率较低,因此迭代更快。另一方面,递归版本使用较少或不使用局部变量,这是一个优势。
【讨论】:
我们需要迭代地实现。如果我们递归实现,如果输入变得非常大(即 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;
}
【讨论】:
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 扩展到两倍。
【讨论】:
我们只有一行来计算它:
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);
}
}
【讨论】:
public static int fact(int i){
if(i==0)
return 0;
if(i>1){
i = i * fact(--i);
}
return i;
}
【讨论】:
public int factorial(int num) {
if (num == 1) return 1;
return num * factorial(num - 1);
}
【讨论】:
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);
}
}
【讨论】:
我从 EDX 得到这个,用它!它称为递归
public static int factorial(int n) {
if (n == 1) {
return 1;
} else {
return n * factorial(n-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;
}
【讨论】:
使用递归是最简单的方法。如果我们想找到的阶乘 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;
}
【讨论】:
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);
}
【讨论】:
使用 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();
}
【讨论】:
使用动态编程是有效的
如果你想用它来一次又一次地计算(比如缓存)
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];
}
【讨论】: