高精度数值运算

我们都知道,int型变量占四个字节,取值范围在 -2147483648~+2147483647 之间,大致范围是 -2* 10^9 ~ +2* 10^9 ,如果这个范围仍不够我们的需求,可以使用 unsigned int型,它的范围会比 int 型大一倍,如果还无法满足,还可以考虑使用 long long(大致范围在 -9* 10^18~ +9* 10^18)或者 unsigned long long 。

当然这些并不是接下来我要介绍的重点,既然本文的标题叫做高精度数值运算,那么肯定有人会疑惑,什么是高精度数值运算?是把算数和结果精确到小数点后多少位那种么?显然不会是这样,所谓高精度数值运算,就是说参与运算的数值太大,大到什么程度呢?大到超出了编译器所能存储的基本数据类型的上限,即比unsigned long long 还要大的数据。
如此大的数据,该怎么运算呢?这就涉及到了高精度数值运算。

不过,在讲解运算之前,还要先解决一个问题:高精度数据的存储。
怎样存储高精度的数据?相信我们很多人都会不约而同地想到:数组!对,就是用数组。
这里我们定义一个数组 t[1000],因为高精度数据往往有很多位,为了使用方便,我们再定义一个变量len,用来存储长度,然后把它们封装成一个结构体,如下:

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

为了方便对每一个结构体变量赋值,还可以对结构体这样定义:

struct bign{
    int t[1000];
    int len;
    bign()//这里是一个初始化结构体的函数,函数名与结构体名相同,可以在每次定义结构体变量的同时进行初始化
    {
        memset(t,0,sizeof(t));//使用memset要添加<string.h>头文件
        len=0;
    }
}

另外,输入高精度数据可以用字符串输入,因此还需要一个转换函数,作用是把字符串转换成数组。
转换函数如下:

void shift(char str[])
{
    bign a;//定义一个结构体数据
    a.len=strlen(str);//获取长度
    for(int i=0;i<a.len;i++)//遍历字符串
    {
        a.t[i]=str[a.len-i-1]-'0';//字符数据变整型 -'0'  倒序输入
    }
    return a;
}

注意:因为输入的字符串是最低位存储数值最高位,故倒序转换为数组后,数组内是最低位存储数值最低位,即个位。

再顺便介绍一下高精度数据之间的比较:

int compare(bign a,bign b)
{
    if(a.len>b.len)
        return 1;//a大
    else if(a.len<b.len)
        return -1;//a小
    else
    {
        for(int i=a.len-1;i>=0;i--)
        {
            if(a.t[i]>b.t[i])
                return 1;
            else
                return -1;
        }
        return 0;//一样大
    }
}

好了,了解了上面的内容后,接下来正式介绍高精度数值运算。
这里仅介绍四种高精度运算,分别是:高精度加法运算,高精度减法运算,高精度数据与低精度数据的乘法运算,以及高精度数据与低精度数据的除法运算。至于高精度与高精度的乘法和除法,将在以后有机会介绍。

【高精度加法运算】
先看一个十分简单的例子:
1 2 5
+ 8 8
2 1 3

第一步:8+5=13>10 13-10=3 进位+1
第二步:2+8+1=11>10 11-10=1 进位+1
第三步:1+1=2<10 结束

将上面的步骤转换成算法的话,就是这种:

bign add(bign a;bign b)//因为需要返回一个结构体类型,故函数类型也为结构体型
{
    bign c;
    int carry=0;//进位设置为0;
    for(int i=0;i<=a.len||i<=b.len;i++)//以较长的为基准
    {
        int temp=a.t[i]+b.t[i]+carry;
        c.t[c.len++]=temp%10; //temp>10则只存储个位,temp<10则全部存入
        carry=temp/10;//这里如果temp<10,则temp为0
    }
    if(carry!=0)//说明temp>10
    {
        c.t[c.len++]=carry;//注意,这里的意思是数组的第len位重新被赋值为carry,但因为carry>10,故len++
    }
    return c;
}

具体完整代码如下:

#include <stdio.h>
#include <string.h>
struct bign{
    	int t[1000];
    	int len;
	bign()
	{
		memset(t,0,sizeof(t));
		len=0;
	}
};
bign shift(char str[])//转换函数 
{
	bign a;
	a.len=strlen(str);//注意strlen与sizeof的区别 
	for(int i=0;i<a.len;i++)
	{
		a.t[i]=str[a.len-i-1]-'0';
	}
	return a;
}
bign add(bign a,bign b)//定义高精度加法函数 
{
	bign c;
	int carry=0;
	for(int i=0;i<a.len||i<b.len;i++)//逐位相加 
	{
		int temp=a.t[i]+b.t[i]+carry;
		c.t[c.len++]=temp%10;//这条语句为易错语句!9 
		carry=temp/10;
	}
	if(carry!=0)
	{
		c.t[c.len++]=carry;
	}
	return c;
}
void print(bign a)//结构体输出函数 
{
	for(int i=a.len-1;i>=0;i--)//注意这里是逆序输出 
	{
		printf("%d",a.t[i]);
	}
}
int main()
{
	char str1[1000],str2[1000];
	gets(str1);
	gets(str2);
	print(add(shift(str1),shift(str2)));
	return 0;
}

【高精度减法运算】
例子就不说了,可以自己尝试着写一两个例子看一看,总之就是把最普通的步骤转换成了代码。
如下:

bign sub(bign a,bign b)
{
    bign c;
    for(int i=0;i<a.len||i<b.len;i++)
    {
        if(a.t[i]<b.d[i])
        {
            a.t[i+1]--;
            a.t[i]+=10;
        }
        c.t[c.len++]=a.t[i]-b.t[i];
    }
    while(c.len-1>=1&&c.t[c.len-1]==0)//差为零,以及多个连续的差为零的情况
    {
        c.len--;
    }
    return c;
}

【高精度与低精度的乘法】
直接上代码:

bign multi(bign a,int b)
{
    bign c;
    int carry=0;
    for(int i=0;i<a.len;i++)
    {
        int temp=a.t[i]*b+carry;
        c.t[c.len++]=temp%10;
        carry=temp/10;
    }
    while(carry!=0)
    {
        c.t[c.len++]=carry%10;
        carry/=10;
    }
    return c;
}

【高精度与低精度的除法】
代码如下:

bign divide(bign a,int b,int &r)//r是余数,这里r采用引用方便传出r的值
{
    bign c;
    c.len=a.len;
    r=0;
    for(int i=a.len-1;i>=0;i--)
    {
        r=r*10+a.t[i];//余数*10与新位结合
        if(r<b)
            c.t[i]=0;//商设置为零
        else
        {
            c.t[i]=r/b;//商作为值
            r=r%b;//获得新的余数
        }
    }
    while(c.len-1>1&&c.t[len-1]==0)//去零
    {
        c.len--;
    }
    return c;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值