c++中带字符串的大数字的阶乘

factorial of big numbers with strings in c++

本文关键字:阶乘 数字 字符串 c++      更新时间:2023-10-16

我正在用字符串执行阶乘程序,因为我需要大于250 的数字的阶乘

我的意图是:

string factorial(int n){
    string fact="1";
    for(int i=2; i<=n; i++){
        b=atoi(fact)*n;
    }
}

但问题是atoi不起作用。如何将字符串转换为整数。

最重要的是,我想知道这种方式的程序是否能以400的阶乘工作吗?

不确定为什么要使用字符串。可能是为了通过不使用整数向量来节省一些空间?这是我使用整数向量存储阶乘和打印的解决方案。适用于400或任何大的数字!

//Factorial of a big number
#include<iostream>
#include<vector>
using namespace std;

int main(){
    int num;
    cout<<"Enter the number :";
    cin>>num;
    vector<int> res;
    res.push_back(1);
    int carry=0;
    for(int i=2;i<=num;i++){
        for(int j=0;j<res.size();j++){
            int tmp=res[j]*i;
            res[j]=(tmp+carry)%10 ;
            carry=(tmp+carry)/10;
        }
        while(carry!=0){
            res.push_back(carry%10);
            carry=carry/10;
        }
    }
    for(int i=res.size()-1;i>=0;i--) cout<<res[i];
    cout<<endl;


    return 0;
}

输入数字:400400的因数:6403452284662389562347970319503005850702583026002959458684445942802397166831436278478647463264676294350575035856810848162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709496713452904770203224349112107975932807951015453726672516278778900093497637657103263503315653498683868313393520243737881577867915068587021827016981974006298302530859129834612622723045583395207596115053022360868104332972551948526743223243866994842243259980555161063594237696139923191340638589956537970147827206606320217379472010321356624613809077942304597360699567595836096158715123822286579549361617654480453222782581840084843641559122945427538480355837451822675900061399560145595206127211192105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000

有一个网站可以为您计算阶乘:http://www.nitrxgen.net/factorialcalc.php.报告:

得到的阶乘为250!长493位。结果还包含62个尾随零(占总数的12.58%)

323285626090910773323208145520243684709484371767378066674794242711282374755511120948881791537102819945092850735318943273093171280899082279103027907128192167652724018926473321804118626100683292536513367893908956993571353017504051317876007772479330654023390061648255522488194365725860573992226641254832982074849137721776650641276858080715312897877767295191399084437747870258917297325515028324178732065818848206478582659808848825554880000000000000000000000000000000000000000000000000000000000000000

许多使用C++CCD_ 1的系统只能工作到1E+308或大约1E+308;250的值!太大了,无法以这样的数量存储。

因此,您需要使用某种多精度算术库,或者是您自己使用C++string值进行设计,或者使用其他广泛使用的多精度库(例如GNU GMP)。

下面的代码使用unsigned double long来计算非常大的数字。

#include<iostream.h>

int main()
{
    long k=1;
    while(k!=0)
    {
        cout<<"nLarge Factorial Calculatornn";
        cout<<"Enter a number be calculated:";
        cin>>k;
        if (k<=33)
        {
            unsigned double long fact=1;
            fact=1;
            for(int b=k;b>=1;b--)
            {
                    fact=fact*b;
            }
            cout<<"nThe factorial of "<<k<<" is "<<fact<<"n";
        }

        else
        {
            int numArr[10000];
            int total,rem=0,count;       
            register int i;              
            //int i;
            for(i=0;i<10000;i++)
            numArr[i]=0;             
            numArr[10000]=1;  
            for(count=2;count<=k;count++)   
            {
            while(i>0)
            {
                total=numArr[i]*count+rem;  
                rem=0;
                if(total>9)
                {
                    numArr[i]=total%10;
                    rem=total/10;
                }
                else
                {
                    numArr[i]=total;    
                }
                i--;             
            }
                rem=0;
                total=0;
                i=10000;
            }
            cout<<"The factorial of "<<k<<" is nn";
            for(i=0;i<10000;i++)            
                {
                    if(numArr[i]!=0 || count==1)  
                    {
                    cout<<numArr[i];
                    count=1;
                }
            }
            cout<<endl;
        }
        cout<<"nn";
    }//while
return 0;
}

输出:

![Large Factorial Calculator
Enter a number be calculated:250
The factorial of 250 is
32328562609091077323208145520243684709948437176737806667479424271128237475551112
09488817915371028199450928507353189432926730931712808990822791030279071281921676
52724018926473321804118626100683292536513367893908956993571353017504051317876007
72479330654023390061648255522488194365725860573992226412548329822048491377217766
50641276858807153128978777672951913990844377478702589172973255150283241787320658
18848206247858265980884882554880000000000000000000000000000000000000000000000000
000000000000][1]

您可以通过添加c_str()来编译atoi,但要获得阶乘还有很长的路要走。目前你身边没有b。如果你有,你仍然可以将int乘以int。所以即使你最终在返回之前将其转换为字符串,你的范围仍然是有限的。在您开始实际使用ASCII进行乘法运算或使用bignum库之前,没有必要使用字符串。

您的阶乘取决于到int的转换,它会很快溢出,所以您希望能够以这种方式计算大阶乘。为了正确地在大数字上实现计算,你需要像在纸上实现计算一样实现逻辑,这是你在小学时很难理解的规则,但将长整型整数视为"原子",而不是单个数字。不要在字符串上这样做,它会非常慢,而且充满了讨厌的转换

p>如果你要求解大于12的数字的阶乘,你需要一种不同于使用atoi的方法,因为它只会给你一个32位的整数,无论你做什么,你都不会从中得到超过20亿(给予或索取)。即使你把数字增加一倍,你也只能达到20或21左右。

写一个字符串乘法例程并不难(相对而言),它取一个小(ish)数字,对每个数字进行乘法运算,并将结果波及到数字(从数字的后面开始,然后填充)。

这是我混淆的代码——它是故意写的,这样你就不能把它当作学校作业来交,但它似乎有效(与乔纳森·勒夫勒答案中的数字相匹配),而且(至少)可以达到20000![要有足够的记忆力]。

std::string operator*(const std::string &s, int x)
{
    int l = (int)s.length();
    std::string r;
    r.resize(l);
    std::fill(r.begin(), r.end(), '0');
    int b = 0;
    int e = ~b;
    const int c = 10;
    for(int i = l+e; i != e;)
    {
        int d = (s[i]-0x30) * x, p = i + b;
        while (d && p > e)
        {
            int t  = r[p] - 0x30 + (d % c);
            r[p] = (t % c) + 0x30;
            d = t / c + d / c;
            p--;
        }
        while (d)
        {
            r = static_cast<char>((d % c) +0x30)+r;
            d /= c;
            b++;
        }
        i--;
    }
    return r;
}

在C++中,最大的整数类型是"long-long",它可以容纳64位内存,所以显然不能存储250!在整数类型中。使用字符串是一个聪明的想法,但你基本上对代码所做的是(我从未使用过atoi()函数,所以我不知道它是否适用于大于1个字符的字符串,但这无关紧要):

  1. 将字符串转换为integer(如果此代码运行良好,则该字符串会立即包含值249!)
  2. 乘以字符串的值

所以,在完成乘法运算后,您甚至不会将整数转换回字符串。即使你这样做了,当你把字符串转换回整数时,你的程序也会崩溃,因为整数无法容纳字符串的值。

我的建议是,对大整数使用一些类。不幸的是,C++中没有可用的,所以你必须自己编码或在互联网上找到一个。但是,别担心,即使你自己编码,如果你想一想,你会发现它并没有那么难。你甚至可以将你的想法与字符串结合使用,即使这不是解决这个问题的最佳方法,但在不使用太多内存的情况下,仍然会在所需时间内产生结果。

这是一个典型的高精度问题。

您可以使用无符号长-长数组,而不是字符串。像这样:

struct node
{
    unsigned long long digit[100000];
}

它应该比字符串快。

但除非您有急事,否则您仍然可以使用字符串。

计算10000可能需要几天时间!。

我喜欢用字符串,因为它很容易写。

#include <bits/stdc++.h>
#pragma GCC optimize (2)
using namespace std;
const int MAXN = 90;
int n, m;
int a[MAXN];
string base[MAXN], f[MAXN][MAXN];
string sum, ans;
template <typename _T>
void Swap(_T &a, _T &b)
{
    _T temp;
    temp = a;
    a = b;
    b = temp;
}
string operator + (string s1, string s2)
{
    string ret;
    int digit, up = 0;
    int len1 = s1.length(), len2 = s2.length();
    if (len1 < len2) Swap(s1, s2), Swap(len1, len2);
    while(len2 < len1) s2 = '0' + s2, len2++;
    for (int i = len1 - 1; i >= 0; i--)
    {
        digit = s1[i] + s2[i] - '0' - '0' + up; up = 0;
        if (digit >= 10) up = digit / 10, digit %= 10;
        ret = char(digit + '0') + ret;
    }
    if (up) ret = char(up + '0') + ret;
    return ret;
}
string operator * (string str, int p)
{
    string ret = "0", f; int digit, mul;
    int len = str.length();
    for (int i = len - 1; i >= 0; i--)
    {
        f = "";
        digit = str[i] - '0';
        mul = p * digit;
        while(mul)
        {
            digit = mul % 10 , mul /= 10;
            f = char(digit + '0') + f;
        }
        for (int j = 1; j < len - i; j++) f = f + '0';
        ret = ret + f;
    }
    return ret;
}
int main()
{
    freopen("factorial.out", "w", stdout);
    string ans = "1";
    for (int i = 1; i <= 5000; i++)
    {
        ans = ans * i;
        cout << i << "! = " << ans << endl;
    }
    return 0;
}

事实上,我知道问题在哪里提出。在我们相乘的时候,就有了实际的问题,当数字相乘并变得越来越大。

该代码经过测试,并给出了正确的结果。

#include <bits/stdc++.h>
using namespace std;
#define mod 72057594037927936   // 2^56  (17 digits)
// #define mod 18446744073709551616 // 2^64 (20 digits) Not supported
long long int prod_uint64(long long int x, long long int y)
{
   return x * y % mod;
}
int main()
{
     long long int n=14, s = 1;
     while (n != 1)
     {
          s = prod_uint64(s , n) ;
          n--;
     }
}

14的扩展输出!=87178291200

逻辑应该是:

unsigned int factorial(int n)
{
    unsigned int b=1;
    for(int i=2; i<=n; i++){
        b=b*n;
    }
    return b;
}

然而,b可能会溢出。所以你可以使用一个更大的积分类型。或者你可以使用浮动类型,这是不准确的,但可以容纳更大的数字。但似乎没有一个内置类型足够大。