大数与高精度的一系列计算(C++)(新手入门)

高精度算法是模拟思想中比较典型的部分,这里列举了一些典型的我个人总结的精度算法(新手入门),一些基本的概念大家可以自己百度查阅

注意这里进行运算的数据都是非负数,但是结果不一定是非负数

1.高精加低精

这里是用一个大数依次加若干个小数,即从90001加到95000共5000次加法,注意这里没有采用输入,如果要用数组存储位数,须用到sstream头文件,将int类型转换为string类型

//大数加小数(无输入)
#include<iostream>
#include<string>
#include<sstream>
#define MAXN 99+4
using namespace std;
int main()
{
    int temp=9;
    int a[MAXN]={};
    stringstream st;
    for(int i=0;i<99;i++)
    {
        st<<temp;//将99个9放入st
    }
    string s;
    s=st.str();//将99个9放入s
    for(int i=0;i<s.size();i++)
    {
        a[i]=s[s.size()-1-i]-'0';//逆序存放,即个位在a[0],依次往后
    }
    for(int i=90001;i<=95000;i++)//从90001加到95000
    {
        int jw=0;
        a[0]+=i;//把小数加入个位
        for(int j=0;j<MAXN;j++)//接下来处理进位
        {
            a[j]+=jw;//加上上一个进位
            jw=a[j]/10;//计算下一次进位的值
            a[j]%=10;//进位后的结果
        }
    }
        int len=MAXN;
        for(int i=len-1;i>=0;i--)//删除前导0
        {
            if(a[i]==0&&len>1)//注意值为0的情况,即使这里不可能,这是一种习惯
            {
                len--;
            }
            else
            {
                break;
            }
        }
        for(int i=len-1;i>=0;i--)//逆序遍历输出
        {
            cout<<a[i];
        }
        cout<<endl;

2.高精加高精

这里采用有输入的情况,先用string对象存储数字,再放入int数组中,高精的算法同样适用于低精,代码如下

//大数加大数
#include<iostream>
#include<string>
#include<algorithm>
#define MAXN 100+4
using namespace std;
int main()
{
    string s1;
    string s2;
    int a[MAXN]={};
    int b[MAXN]={};
    cin>>s1>>s2;//输入两个大数
    for(int i=0;i<s1.size();i++)
    {
        a[i]=s1[s1.size()-1-i]-'0';//将大数逆序放入a数组
    }
    for(int i=0;i<s2.size();i++)
    {
        b[i]=s2[s2.size()-1-i]-'0';//同上
    }
    /*它规定了一个加法能够达到的
    最大的可能位数,以此之后遍历
    的时候不用遍历到MAXN*/
    int lena=max(s1.size(),s2.size())+1;//+1是因为可能进位
    int jw=0;
    for(int i=0;i<lena;i++)
    {
        a[i]+=b[i]+jw;
        jw=a[i]/10;
        a[i]%=10;
    }
    for(int i=lena-1;i>=0;i--)//删除前导0
    {
        if(a[i]==0&&lena>1)
        {
            lena--;
        }
        else
        {
            break;
        }
    }
    for(int i=lena-1;i>=0;i--)//逆序遍历
    {
        cout<<a[i];
    }
    cout<<endl;
}

3.高精减低精(低精减高精)

这里和加法区别不大,依然用个位去减低精,然后向上借位即可,如果是低精减高精,加个负号,其余不变,代码如下

//大小数互减
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
    string s;
    cin>>s;
    int b;
    cin>>b;
    int a[MAXN]={};
    for(int i=0;i<s.size();i++)
    {
        a[i]=s[s.size()-1-i]-'0';//放入数组
    }
    int c=0;//借位
    a[0]-=b;//用个位减去小数
    for(int i=0;i<s.size();i++)
    {
        a[i]-=c;//减去借位
        c=0;//重置借位为0
        if(a[i]<0)
        {
            while(a[i]<0)
            {
                a[i]+=10;//每次从下一位借1
                c++;//借位加1
            }
        }
        else//这里到末尾都没有借位,不动即可
        {
            break;
        }
    }
    int len=s.size();
    for(int i=len-1;i>=0;i--)//删前导0
    {
        if(a[i]==0&&len>1)
        {
            len--;
        }
        else
        {
            break;
        }
    }
    for(int i=len-1;i>=0;i--)
    {
        cout<<a[i];
    }
    cout<<endl;
    return 0;
}

4.高精减高精

这里判断了一下大小,用大减小即可,其他无变化,代码如下

//大数减大数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
    string s1;
    string s2;
    cin>>s1>>s2;
    if(s1.size()<s2.size()||s1.size()==s2.size()&&s1<s2)//判断大小
    {
        cout<<"-";
        swap(s1,s2);
    }
    int a[MAXN]={};
    int b[MAXN]={};
    for(int i=0;i<s1.size();i++)
    {
        a[i]=s1[s1.size()-1-i]-'0';
    }
    for(int i=0;i<s2.size();i++)
    {
        b[i]=s2[s2.size()-1-i]-'0';
    }
    int c=0;
    for(int i=0;i<s1.size();i++)
    {
        a[i]-=b[i]+c;
        c=0;
        while(a[i]<0)
        {
            a[i]+=10;
            c++;
        }
    }
    int len=s1.size();
    for(int i=len-1;i>=0;i--)
    {
        if(a[i]==0&&len>1)
        {
            len--;
        }
        else
        {
            break;
        }
    }
    for(int i=len-1;i>=0;i--)
    {
        cout<<a[i];
    }
    cout<<endl;
    return 0;
}

5.高精乘低精

这里只要注意低精会和高精的每一位相乘,注意进位即可,非常简单,这种题目典型的应用就是高阶乘的运算,代码如下

#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
    string s;
    int b;
    int a[MAXN]={};
    cin>>s;
    cin>>b;
    for(int i=0;i<s.size();i++)
    {
        a[i]=s[s.size()-1-i]-'0';
    }
    int jw=0;
    for(int i=0;i<MAXN;i++)
    {
        a[i]=a[i]*b+jw;
        jw=a[i]/10;
        a[i]%=10;
    }
    int len=MAXN;
    for(int i=len-1;i>=0;i--)
    {
        if(a[i]==0&&len>1)
        {
            len--;
        }
        else
        {
            break;
        }
    }
    for(int i=len-1;i>=0;i--)
    {
        cout<<a[i];
    }
    cout<<endl;
    return 0;
}

6.高精乘高精

大数乘大数在大数乘小数的基础上延申,即交叉相乘,有些代码把交叉相乘和处理进位放在一起,但我觉得不直观,即使少遍历了一遍,但是然并卵,这里交叉相乘后再统一处理进位,看起来爽一些,代码如下

//大数乘大数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
    string s1;
    string s2;
    int a[MAXN]={};
    int b[MAXN]={};
    /*由于a数组的数据要多
    次用到,所以决定另开辟
    一个数组*/
    int c[MAXN]={};
    cin>>s1;
    cin>>s2;
    for(int i=0;i<s1.size();i++)
    {
        a[i]=s1[s1.size()-1-i]-'0';
    }
    for(int i=0;i<s2.size();i++)
    {
        b[i]=s2[s2.size()-1-i]-'0';
    }
    for(int i=0;i<s1.size();i++)//采用交叉相乘
    {
        for(int j=0;j<s2.size();j++)
        {
            c[i+j]+=a[i]*b[j];
        }
    }
    int jw=0;
    for(int i=0;i<MAXN;i++)//开始处理进位
    {
        c[i]+=jw;
        jw=c[i]/10;
        c[i]%=10;
    }
    int len=MAXN;
    for(int i=len-1;i>=0;i--)
    {
        if(c[i]==0&&len>1)
        {
            len--;
        }
        else
        {
            break;
        }
    }
    for(int i=len-1;i>=0;i--)
    {
        cout<<c[i];
    }
    cout<<endl;
    return 0;
}

7.高精除低精

这里用每一位去除除数,不够则把余数放到下一位去除,找到被除数就能得到商和余数,比较简单,代码如下

//大数除小数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
    string s;
    cin>>s;
    int a[MAXN]={};
    int b;
    cin>>b;
    for(int i=0;i<s.size();i++)
    {
        a[i]=s[s.size()-1-i]-'0';
    }
    int x=0;
    for(int i=s.size()-1;i>=0;i--)//一位一位除
    {
        int temp=x*10+a[i];//这是每次除法的被除数
        a[i]=temp/b;//每次除法的商
        x=temp%b;//每次得到的余数
    }
    int len=s.size();
    for(int i=len-1;i>=0;i--)
    {
        if(a[i]==0&&len>1)
        {
            len--;
        }
        else
        {
            break;
        }
    }
    for(int i=len-1;i>=0;i--)
    {
        cout<<a[i];
    }
    cout<<"......"<<x<<endl;
    return 0;
}

8.高精除高精

这里相对比较复杂,首先是数组比较与移位函数,数组比较很简单,移位函数就是将数组高位对齐,这里开辟了一个temp数组用来存储高位对齐后的除数,即扩大倍数后的除数,原理上与减法相同,但是如果只有减法必TLE,移位合理扩大了倍数,我之前也写了一个相似的代码,但是因为效率太低而舍弃,扩大倍数也需要合理的方法,否则不能保证算法的效率,代码如下

#include<iostream>
#include<string>
#include<sstream>
#include<cstring>
#define MAXN 100+4
using namespace std;
/*长度需要全局声明,
以便函数使用*/
int lena;
int lenb;
int lenc;
int lentemp;
int cmp(int *a,int *b)//比较数组的数据大小
{
    stringstream st1;
    stringstream st2;
    for(int i=MAXN-1;i>=0;i--)
    {
        st1<<a[i];
        st2<<b[i];
    }
    string s1=st1.str();
    string s2=st2.str();
    if(s1==s2)
    {
        return 0;
    }
    else if(s1.size()<s2.size()||s1.size()==s2.size()&&s1<s2)
    {
        return -1;
    }
    else if(s1.size()>s2.size()||s1.size()==s2.size()&&s1>s2)
    {
        return 1;
    }
}
/*移位函数,能够使除数与被除数
高位对齐,将b数组的数移到temp数组
的dex下标的位置*/
void numcpy(int *b,int *temp,int dex)
{
    for(int i=0;i<lenb;i++)
    {
        temp[i+dex]=b[i];
    }
}
int main()
{
    string s1;
    string s2;
    int a[MAXN]={};
    int b[MAXN]={};
    int c[MAXN]={};
    int temp[MAXN]={};
    cin>>s1>>s2;
    lena=s1.size();
    lenb=s2.size();
    /*+1是考虑到被除数
    位数减去除数位数不
    一定是商的位数,
    例如625/25=25*/
    lenc=lena-lenb+1;
    for(int i=0;i<s1.size();i++)
    {
        a[i]=s1[s1.size()-1-i]-'0';
    }
    for(int i=0;i<s2.size();i++)
    {
        b[i]=s2[s2.size()-1-i]-'0';
    }
    for(int i=lenc-1;i>=0;i--)
    {
        memset(temp,0,sizeof(temp));//temp数组清空
        numcpy(b,temp,i);//高位对齐
        while(cmp(a,temp)>=0)//被除数比temp大
        {
            c[i]++;//商的第i+1位加1
            for(int j=0;j<lena;j++)//高精度减法,详情见之前的代码
            {
                if(a[j]<temp[j])
                {
                    a[j+1]--;
                    a[j]+=10;
                }
                a[j]=a[j]-temp[j];
            }
        }
    }
    for(int i=lenc-1;i>=0;i--)//商删除前导0
    {
        if(c[i]==0&&lenc>1)
        {
            lenc--;
        }
        else
        {
            break;
        }
    }
    for(int i=lena-1;i>=0;i--)//余数删除前导0
    {
        if(a[i]==0&&lena>1)
        {
            lena--;
        }
        else
        {
            break;
        }
    }
    for(int i=lenc-1;i>=0;i--)
    {
        cout<<c[i];
    }
    cout<<"......";
    for(int i=lena-1;i>=0;i--)
    {
        cout<<a[i];
    }
    cout<<endl;
    return 0;
}
/*输出效果
输入样例
150 32
输出样例
4......22
输入样例
123123123123123123123123123123123 123456
输出样例
997303680040849558734473197......114291*/


如果有错误或者不足,希望各位大佬不吝赐教!

发布了3 篇原创文章 · 获赞 1 · 访问量 104

猜你喜欢

转载自blog.csdn.net/BakenJ/article/details/104939307