也许我有点太晚了,但我还是会添加我的建议和解决方案。它可能会在下次帮助您(和其他人)。
stackoverflow 问题的最佳解决方案实际上是根本不使用递归:
int fac(int n){
int res=1;
for(int i = 0; i <= n; ++i){
res *= i;
}
return res;
}
由于时间(函数调用)和资源(堆栈)消耗,递归实际上在编程时被取消了。在许多情况下,如果需要保存“当前位置”(在 c++ 中可以使用vector),可以使用循环和带有简单弹出/推送操作的堆栈来避免递归。在阶乘的情况下,甚至不需要堆栈,但如果您正在迭代 tree datastructure,例如,您将需要一个堆栈(不过取决于实现)。
现在您遇到的另一个问题是int 大小的限制:如果您使用 32 位整数,则不能超过 fac(12),而对于 64 位整数,则不能超过 fac(20)。这可以通过使用实现大数运算的外部库来解决(如GMP library 或 Boost.multiprecision as SenselessCoder 提到的)。但是您也可以从 Java 创建您自己版本的 BigInteger 类类,并像我所拥有的那样实现基本操作。我在示例中只实现了乘法,但加法非常相似:
#include <iostream>
#include <vector>
#include <stdio.h>
#include <string>
using namespace std;
class BigInt{
// Array with the parts of the big integer in little endian
vector<int> value;
int base;
void add_most_significant(int);
public:
BigInt(int begin=0, int _base=100): value({begin}), base(_base){ };
~BigInt(){ };
/*Multiply this BigInt with a simple int*/
void multiply(int);
/*Print this BigInt in its decimal form*/
void print();
};
void BigInt::add_most_significant(int m){
int carry = m;
while(carry){
value.push_back(carry % base);
carry /= base;
}
}
void BigInt::multiply(int m){
int product = 0, carry = 0;
// the less significant part is at the beginning
for(int i = 0; i < value.size(); i++){
product = (value[i] * m) + carry;
value[i] = product % base;
carry = product/base;
}
if (carry)
add_most_significant(carry);
}
void BigInt::print(){
// string for the format depends on the "size" of the base (trailing 0 in format => fill with zeros if needed when printing)
string format("%0" + to_string(to_string(base-1).length()) + "d");
// Begin with the most significant part: outside the loop because it doesn't need trailing zeros
cout << value[value.size()-1];
for(int i = value.size() - 2; i >= 0; i-- ){
printf(format.c_str(), value[i]);
}
}
主要思想很简单,BigInt 通过将其little endian 表示切割成碎片来表示一个大十进制数。这些碎片的长度取决于您选择的底座。 只有当你的基数是 10 的幂时才有效:如果你选择 10 作为基数,每块代表一个数字,如果你选择 100 (= 10^2) 作为基数,每块代表两个从末尾开始的连续数字(请参阅小端),如果您选择 1000 作为基数(10^3),则每块将代表三个连续数字,......等等。假设您的基数为 100,那么 12765 将是 [65, 27, 1],1789 将是 [89, 17],505 将是 [5, 5] (= [05,5]),...基数为 1000:12765 将是 @987654337 @,1789 将是 [789, 1],505 将是 [505]。
那么乘法就有点像我们在学校学过的纸上乘法:
- 从
BigInt 的最低部分开始
- 乘以乘数
- 该乘积的最低部分(= 基数的乘积模数)成为最终结果的对应部分
- 该产品的“较大”部分将添加到以下部分的产品中
- 下一块进入第 2 步
- 如果没有剩余部分,则将
BigInt 的最后一部分的剩余较大部分添加到最终结果中
例如:
9542 * 105 = [42, 95] * 105
lowest piece = 42 --> 42 * 105 = 4410 = [10, 44]
---> lowest piece of result = 10
---> 44 will be added to the product of the following piece
2nd piece = 95 --> (95*105) + 44 = 10019 = [19, 00, 1]
---> 2nd piece of final result = 19
---> [00, 1] = 100 will be added to product of following piece
no piece left --> add pieces [0, 1] to final result
==> 3242 * 105 = [42, 32] * 105 = [10, 19, 0, 1] = 1 001 910
如果我使用上面的类来计算 1 到 30 之间所有数字的阶乘,如下面的代码所示:
int main() {
cout << endl << "Let's start the factorial loop:" << endl;
BigInt* bigint = new BigInt(1);
int fac = 30;
for(int i = 1; i <= fac; ++i){
bigint->multiply(i);
cout << "\t" << i << "! = ";
bigint->print();
cout << endl;
}
delete bigint;
return 0;
}
它会给出以下结果:
Let's start the factorial loop:
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = 51090942171709440000
22! = 1124000727777607680000
23! = 25852016738884976640000
24! = 620448401733239439360000
25! = 15511210043330985984000000
26! = 403291461126605635584000000
27! = 10888869450418352160768000000
28! = 304888344611713860501504000000
29! = 8841761993739701954543616000000
30! = 265252859812191058636308480000000
对于冗长的答案,我深表歉意。我试图尽可能简短,但仍要完整。随时欢迎提问
祝你好运!