高精度减法运算

作者留言:初学者写的代码,想法和代码可能会比较低端,正在改进中,大佬可以给点建议~~

实现目的:在运算一些长度较长的数字,而计算机的运算范围不足以实现运算要求时,实行高精度运算。这里主要解决减法运算。

运算原理:因为数字长度过长,无法通过直接的相减以实现要求,所以引入了字符串,通过把每一位数字存进字符串,对每一位字符串的相减得出结果。

主要思路:任意两数相减,有很多的情况。所以要分5步操作。

一.区分大小:那么首先要区分大数和小数,这里主要通过区分存入字符串的长度来区分,字符串长的则大,字符串短的则小,当字符串相等的时候,先找出从高位到低位第一个不相等位数,再判别两数在此位数的大小,大的则大,小的则小,若是相等则直接输出0,不需要进入代码区中的相减运算,否则会触发下面讲到的去前导0的bug。(当两个数相等时:例如100-100 根据计算结果会为000,若去前导0,则会把3个0全部去掉,所以无需去前导0,直接输出0)

二.转型存放:区分完大小,要将两个字符串变成整型倒序存放进容器,因为设置的容器A和B总是以大减小,所以大数放A容器,小数放B容器。然后输出的结果则设置为C容器。

三.运算设置:设置相减调用区,相减的原理则是对位相减,对位上都有数字直接减,不够减则借位+10,被借位-1,得出的数再插进C容器;若是对位上只剩下较大的数,且较大的数上的位数不为负数,若为负数也要借位+10,被借位-1,再插入C容器。

四.去前导0操作:最后会得到一个C容器,C容器中的数字并不是我们所要的答案,首先我们需要去掉前导0,把最前面不要的0去掉。

五.输出:由于我们是倒序存放数字,所以再输出的时候也需要倒序输出。在输出的时候应该注意,若输出的第一个数小于第二个数,则需要在倒序输出C容器前面先输出“-”符号。因为在步骤二中我们无论怎样都是把较大的数放进A容器,较小的数存在B容器,得出的结果始终是正数。若输出的第一个数大于等于第二个数,直接倒序输出。

主要事项:详细见代码区

涉及重要的一些知识点:

1.容器的定义和对容器中插入的操作(3中有删除操作)

vector<int>A;//定义A容器
A.push_back(1);//将1插入A容器的尾部

2.整型和字符型之间的转换

字符型转化为整型

string   a;//定义a为字符串
cin>>a;//输入a
a[i]=a[i]-'0';// 把字符串的每一个变成整型,可以直接使用,详细见代码区的使用

整形转化为字符型

itoa()原型:  char *itoa( int value, char *string,int radix);
原型说明:
输入参数:
value:要转换的数据。
string:目标字符串的地址。
radix:转换后的进制数,可以是10进制、16进制等,范围必须在 2-36。
功能:将整数value 转换成字符串存入string 指向的内存空间 ,radix 为转换时所用基数(保存到字符串中的数据的进制基数)。
返回值:函数返回一个指向 str,无错误返回。
注意:itoa不是一个标准的c函数,他是windows特有的,跨平台写程序,要用sprintf。
使用例子:
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
int main(){
    int number = 123456;
    char str[20];
    itoa(number,str,10);
    printf("integer=%d,string=%s\n",number,str);
    cout<<"str[0]: "<<str[0]<<endl; 
}

3.去前导0的实现

方法一:(if语句和for循环)

int last;
	for(int i=C.size()-1;i>=0;i--)
	 {	 
		if(C[i]!=0) 
	    {
        last=i; //标记第一个不是0的位数
        break;
     }
	    //从第一个不是0的开始输出 	
	    for(int i=last;i>=0;i--)	
		cout<<C[i];
		}

方法二:(while循环和,back()和pop的结合使用)

	while(C.size()>1&&C.back()==0) C.pop_back();
//当长度大于1并且上一位是0的时候就把最后的0删除,长度大于1的目的是防止答案为0
//push用于插入 pop用于删除

4.字符串长度和容器长度的使用方法

vector<int>A;
A.size();//表示容器A的长度
 string a;
a.size();//表示字符串的长度

源代码:

#include<bits/stdc++.h>
#include<string>
using namespace std;
//此时容器A存放的都是较大的数字,B容器存放的都是较小的数字
vector<int> sub(vector<int> A,vector<int> B) //两个容器相减   
{ 
    vector<int>C;
	for(int i=0;i<A.size()||i<B.size();i++)
	{   
	   if((i<A.size())&&(i<B.size()))     //此时检查的位数两个容器都有数 
	    {	
		  if((A[i]<B[i]))       //当此时A容器的数不够B容器减的时候 
	      {
		  A[i]+=10;              //先给A容器加10 
	      C.push_back(A[i]-B[i]);  
	      A[i+1]-=1;     //因为前面加10,所以下一位就要减1 
	      }
	        else C.push_back(A[i]-B[i]);
    	}   
     	if((i<=A.size())&&(i>=B.size()))      //此时检查的位数A容器还有,但是B容器已经没有,就直接输出A容器的数字 
	   {
	  	 if(A[i]<0) {A[i]+=10; A[i+1]-=1;}     //如果此时的数字正好是0,又被前面的数字借走导致成为负数,就加10,往后数-1; 
		C.push_back(A[i]);    
		}
	} 
	return C;
}
int main()
{
	string a,b;        //定义两个字符串 
	vector<int>A,B;    //定义两个容器存放字符串 
	cin>>a>>b;         //输入字符串 
if(a.size()!=b.size())
{ 
	if(a.size()>b.size())    //当第一个数的长度比第二个数的长度长 
	{
	for(int i=a.size()-1;i>=0;i-- )   A.push_back(a[i]-'0');//将字符串转化为数字
	for(int i=b.size()-1;i>=0;i--)   B.push_back(b[i]-'0');  //同上 
	vector<int>C=sub(A,B);
	//去前导0 
	int last;
	for(int i=C.size()-1;i>=0;i--)
					    {	 
						if(C[i]!=0)  
						{last=i;    //标记第一个不是0的位数 
					    break;
						}
					    }
 
    //输出 
     for(int i=last;i>=0;i--)	
   		cout<<C[i];
   		
	}
	//当第一个数的长度比第二个数的长度段 
		if(a.size()<b.size()) 
		{
			//存放的容器对调 
		for(int i=a.size()-1;i>=0;i-- )   B.push_back(a[i]-'0');//将字符串转化为数字,此时 
		for(int i=b.size()-1;i>=0;i--)   A.push_back(b[i]-'0');  //同上 
		vector<int>C=sub(A,B);
		//去前导0 	
		int last;
	for(int i=C.size()-1;i>=0;i--)
				    {	 
					if(C[i]!=0) 
				 {last=i; //标记第一个不是0的位数
				    break;
				}
				    }
	    //输出 
	    //因为第一个数小于第二个数,所以要输出负号 
	    cout<<"-"; 
				
	    for(int i=last;i>=0;i--)	
		cout<<C[i];
		}
 
}
 
	//当两个位数相等时 
		if(a.size()==b.size()) 
		{  
		int rem=0;	
		int flag=0;
		//两个位数相等,所以要找到两个数从高位到低位第一个不同的数字 
		for(int i=0;i<a.size();i++)
			{
				if(a[i]!=b[i])  { rem=i;flag++; break;}//有不同数字,flag++,说明rem被赋值 
	            		
			}
	
		//若第一个数大于第二个数 
			if(flag!=0&&a[rem]>b[rem])
		{
		for(int i=a.size()-1;i>=0;i-- )   A.push_back(a[i]-'0');//将字符串转化为数字
		for(int i=b.size()-1;i>=0;i--)   B.push_back(b[i]-'0');  //同上 
		vector<int>C=sub(A,B);
	//去前导0 
		int last;
			for(int i=C.size()-1;i>=0;i--)
		    {	 
			if(C[i]!=0)  
			{
			last=i;  //标记第一个不是0的位数
		    break;
			}
		    }
		    //输出 
		    for(int i=last;i>=0;i--)	
			cout<<C[i];
		}
		//若第一个数小于第二个数 
		if(flag!=0&&a[rem]<b[rem])
		{
			
				for(int i=a.size()-1;i>=0;i-- )   B.push_back(a[i]-'0');//将字符串转化为数字
					for(int i=b.size()-1;i>=0;i--)   A.push_back(b[i]-'0');  //同上 
			
		vector<int>C=sub(A,B);
		//去前导0 
		int last;
		for(int i=C.size()-1;i>=0;i--)
	    {	 
		if(C[i]!=0) 
	    {
		last=i;  //标记第一个不是0的位数
	    break;}
	    }
	    //输出 
	    cout<<"-";    
	    for(int i=last;i>=0;i--)	
		cout<<C[i];
		}
			//检查到最后若是都相同 ,flag==0,说明rem没有被赋值,两数完全相等
					if(flag==0) cout<<"0"; //当两个数完全相同时,会输出a长度个 0,再进行去除前导0会没有数值 ,所以此时直接输出0 
		}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值