大数问题 大整数运算

简介

对于A+B,如果A和B是有着1000个数位的整数,就不可以用基本的数据类型如int来存储了。这时只可以老实地模拟加减乘除的过程。大整数又称为高精度整数,其含义就是用基本数据类型无法存储其精度的整数。

大整数的存储

我们可以用数组来存储大整数,比如用int型数组d[1000],这个数组的每一位就代表存放整数的每一位。数组的高下标存储的是整数的高位,低下标存储的是整数的低位。

为了方便获取大整数的长度,一般定义一个int型变量len来记录长度,并与d数组构成结构体。

struct bign
{
    int d[1000];
    int len;
};

最好在定义结构体之后马上对其进行初始化,防止后续忘记。可以在结构体中直接设置构造函数。

struct bign
{
    int d[1000];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

在输入大整数的时候,一般都是先用字符串读入,然后再把字符串另存至结构体。注意,要倒着存储。

bign change(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i

比较2个大整数的大小时,先比较2者的len,如果不相等,谁大谁的值就大。如果相等,从高位一次比较。

int compare(bign a,bign b)
{
    if(a.len>b.len)
        return 1;
    else if(a.len=0;i--)
        {
            if(a.d[i]>b.d[i]) return 1;
            else if(a.d[i]

大整数的四则运算

(1)高精度加法(2)高精度减法 (3)高精度与低精度的乘法(4)高精度与低精度的除法

一般不会考虑高精度与高精度的乘除法。

高精度加法

回忆小学时期的加法

大数问题 大整数运算_第1张图片

从低位开始。

7+5=12   保留个位数2,向高位进1

4+6=10,再加上进位的1为11,保留个位数1,向高位进1

1+0=1,再加上进位的1,为2。

因此每一位进行加法的步骤:将该位上2个数字和进位相加,取个位数作为该位结果,取十位数作为新的进位。

bign add(bign a,bign b)   //高精度A+B
{
    bign c;
    int carry=0    //进位,初始位0;
    for(int i=0;i
#include 
#include 
#include 

struct bign
{
    int d[1000];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i=0;i--)
    {
        printf("%d",a.d[i]);
    }
}

int main()
{
   char s1[100],s2[100];
   scanf("%s%s",s1,s2);
   bign a=change(s1);
   bign b=change(s2);
   print(add(a,b));
   return 0;
}

这样的写法是2个非负整数  如果一方是负的,可以再转换到数组时去掉负号,采用高精度减法,如果都是负的,采用高精度加法,最后结果取负。

高精度减法

回忆小学时期的减法

大数问题 大整数运算_第2张图片

依旧从低位开始

5-7 失败,从高位借1,4变为3,10+5-7=8

3-6失败,从高位借1,1变为0,10+3-6=7

0-0=0    (要特别注意:减法后高位可能存在0,要忽视,但又要保证至少有一位数)

bign sub(bign a,bign b)
{
    bign c;
    for(int i=0;i=1&&c.d[c.len-1]==0)    //去除高位0,同时保证至少一位最低位
    {
        c.len--;
    }
    return c;

}

高精度乘法

高精度乘法这里指bign类型与int类型的乘法,其与之前的乘法运算有点不同。以147*35为例,这里把147视为bign类型数据,35视为int类型。在求积中始终把35看作整体。

大数问题 大整数运算_第3张图片

7*35=245   取个位数5作为该位结果,高位24作为进位

4*35=140,加上进位24,164  把个位数4作为该位结果,高位16作为进位。

1*35=35,加上进位16,得51,把个位数1作为该位结果,高位5作为进位。

没有数继续乘了,就把进位5直接作为结果的高位。(注意在没数可乘时,如果进位大于10,需要循环进位)

bign multi(bign a,int b)
{
    bign c;
    int carry=0;    //进位
    for(int i=0;i

高精度与高精度乘法

首先说一下乘法计算的算法,从低位向高位乘,在竖式计算中,我们是将乘数第一位与被乘数的每一位相乘,记录结果,之后,用第二位相乘,记录结果并且左移一位,以此类推,直到计算完最后一位,再将各项结果相加,得出最后结果。

计算的过程基本上和小学生列竖式做乘法相同。为了编程方便,并不急于处理进位,而是将进位问题留待最后统一处理。

    总结一个规律: 即一个数的第i 位和另一个数的第j 位相乘所得的数,一定是要累加到结果的第i+j 位上。这里i, j 都是从右往左,从0 开始数。
    ans[i+j] = a[i]*b[j];

    另外注意进位时要处理,当前的值加上进位的值再看本位数字是否又有进位;前导清零。

#include 
#include 
#include 
#include 
using namespace std;

int size_plus;

void multi(string &s1,string &s2,int c[])
{
    int n=s1.size();
    int m=s2.size();
    int a[n];
    int b[m];
    int i,j;
    
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    
    for(j=0,i=n-1;i>=0;i--)
    {
        a[j++]=s1[i]-'0';
    }
    
    for(j=0,i=m-1;i>=0;i--)
    {
        b[j++]=s2[i]-'0';
    }
    
    for(i=0;i>s1>>s2;
    int size1=s1.size();
    int size2=s2.size();
    size_plus=size1+size2+5;
    
    int res[size_plus];
    memset(res,0,sizeof(res));
    multi(s1,s2,res);
    
    int i;
    for(i=size_plus-1;i>=0;i--)
    {
        if(res[i]!=0)
            break;
    }
    int len=i+1;
    for(int j=len-1;j>=0;j--)
    {
        printf("%d",res[j]);
    }
    return 0;
}

 

高精度与低精度的除法

除法运算与小学时的运算大致相同

大数问题 大整数运算_第4张图片

1与7比较,不够除,商为0,余数为1

余数1和新位2组成12,12与7比较,够除,商为1,余数为5

余数5与新位3组合为53,53与7比较,够除,商为7,余数为4

余数4与新位4组合为44,44与7比较,够除,商为6,余数为2;

可以看出:上一步的余数乘以10加上该步的位,得到该步的临时被除数,将其与除数比较。若不够除,则商为0.要注意减法后高位可能会有多余的0,要忽视他们,但也要保证至少有一位数。

bign division(bign a,int b,int &r)   //有的题目野火要求球的余数。
{
    bign c;
    c.len=a.len;
    for(int i=a.len-1;i>=0;i--)   //从高位开始
    {
        r=r*10+a.d[i];
        if(r=1&&c.d[c.len-1]==0)
    {
        c.len--;
    }
    return c;
}

整体测试

#include 
#include 
#include 

struct bign
{
    int d[1000];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change_to_bign(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i=1&&c.d[c.len-1]==0)
    {
        c.len--;
    }
    return c;

}

bign multi(bign a,int b)
{
    bign c;
    int carry=0;    //进位
    for(int i=0;i=0;i--)   //从高位开始
    {
        r=r*10+a.d[i];
        if(r=1&&c.d[c.len-1]==0)
    {
        c.len--;
    }
    return c;
}

void print(bign a)
{
    for(int i=a.len-1;i>=0;i--)
    {
        printf("%d",a.d[i]);
    }
}

int main()
{
   char s1[100],s2[100];

   //模拟加法
   printf("请输入要进行加法操作的2个数\n");
   scanf("%s%s",s1,s2);
   bign a=change_to_bign(s1);
   bign b=change_to_bign(s2);
   printf("%s+%s=",s1,s2);
   print(add(a,b));
   printf("\n");

   //模拟减法
   printf("请输入要进行减法操作的2个数\n");
   scanf("%s%s",s1,s2);
   a=change_to_bign(s1);
   b=change_to_bign(s2);
   printf("%s-%s=",s1,s2);
   print(sub(a,b));
   printf("\n");

   //模拟乘法
   printf("请输入要进行乘法操作的2个数\n");
   scanf("%s%s",s1,s2);
   bign f=change_to_bign(s1);
   int d=change_to_int(s2);
   printf("%s*%s=",s1,s2);
   print(multi(f,d));
   printf("\n");

   //模拟除法
   printf("请输入要进行除法操作的2个数\n");
   int r=0;
   scanf("%s%s",s1,s2);
   a=change_to_bign(s1);
   int e=change_to_int(s2);
   printf("%s/%s=",s1,s2);
   print(division(a,e,r));
   printf(" %s%%%s=%d",s1,s2,r);
   printf("\n");
}

大数问题 大整数运算_第5张图片

题目一   幂运算

给定两个数R和n,输出R的n次方,其中0.0

大数问题 大整数运算_第6张图片

#include 
#include 

struct bign
{
    int d[127];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change_str_to_bign(char str[],int *length)
{
    bign c;
    int len_=strlen(str);
    for(int i=len_-1;i>=0;i--)
    {
        if(str[i]=='.')
        {
            *length=len_-1-i;
        }
        else
            c.d[c.len++]=str[i]-'0';
    }
    return c;
}

int change_str_to_int(char str[])
{
    int c=0;
    int len_=strlen(str);
    for(int i=0;i=0;i--)
           {
               printf("%d",result.d[i]);
           }
       }

       //不是纯小数
        else
        {
            int j=0;
            while(result.d[j]==0&&j<=number_of_minus-1)
            {
                j++;
            }
            for(int i=result.len-1;i>=j;i--)
            {
                if(i+1==number_of_minus)
                    printf(".");
                printf("%d",result.d[i]);
            }
        }

    }
    return 0;

}

但是放到题目里边运行,总是提示我运行时间超时!可能是结构体很占用时间?

用字符串或数组表示大数,否则无法精确表示答案1的情况。同时注意2数相乘的位数。

函数BigDataMulti用于计算当前计算值(从数组尾到数组头为数字)与底数的乘积

#include 
#include 

int len;

void BigDataMulti(int a[],int data)
{
    int i;
    int carry=0;
    for(i=0;i=0;i--)
            {
                printf("%d",result[i]);
            }
        }

        else
        {
            int j=0;
            while(result[j]==0&&j<=position-1)   //去掉尾部的0,但也要防止非小数部分的0也被去掉。很重要!
            {
                j++;
            }
            for(int i=len-1;i>=j;i--)
            {
                if(i+1==position)
                    printf(".");
                printf("%d",result[i]);
            }


        }


    }
    return 0;
}

高精度加减乘除推荐博客

 

你可能感兴趣的:(数据结构)