这是c++在刷题过程中的必经之路:大数计算。
很经典的问题。主要就是因为c++中数值范围,无法计算大整数,以及POJ中1001也提到了——大小数。
总之,这种题最重要的就是一个函数,这个函数思想掌握了,以后可以用更简单的语句实现:
bigIn operator +(const bigIn &A) const{
bigIn ret;
int carry=0;
for(int i=0;i<A.size||i<size;i++)
{
int tmp=A.dig[i]+dig[i]+carry;
carry=tmp/10000;
tmp%=10000;
ret.dig[ret.size++]=tmp;
}
if(carry!=0)
{
ret.dig[ret.size++]=carry;//保存进位
}
return ret;
}
意思就是,从前往后,依次进行相加,判断是否有余数。
这里的前,其实是指原本字符串的后。
因为最开始读入的时候是从后往前读入的,(真的佩他们想得出)
下面这个题目就是这样的:
题目描述
在计算机中,由于处理器位宽限制,只能处理有限精度的十进制整数加减法,比如在32位宽处理器计算机中,
参与运算的操作数和结果必须在-2^31~2^31-1之间。如果需要进行更大范围的十进制整数加法,需要使用特殊
的方式实现,比如使用字符串保存操作数和结果,采取逐位运算的方式。如下:
9876543210 + 1234567890 = ?
让字符串 num1="9876543210",字符串 num2="1234567890",结果保存在字符串 result = "11111111100"。
-9876543210 + (-1234567890) = ?
让字符串 num1="-9876543210",字符串 num2="-1234567890",结果保存在字符串 result = "-11111111100"。
要求编程实现上述高精度的十进制加法。
要求实现方法:
public String add (String num1, String num2)
【输入】num1:字符串形式操作数1,如果操作数为负,则num1的前缀为符号位'-'
num2:字符串形式操作数2,如果操作数为负,则num2的前缀为符号位'-'
【返回】保存加法计算结果字符串,如果结果为负,则字符串的前缀为'-'
注:
(1)当输入为正数时,'+'不会出现在输入字符串中;当输入为负数时,'-'会出现在输入字符串中,且一定在输入字符串最左边位置;
(2)输入字符串所有位均代表有效数字,即不存在由'0'开始的输入字符串,比如"0012", "-0012"不会出现;
(3)要求输出字符串所有位均为有效数字,结果为正或0时'+'不出现在输出字符串,结果为负时输出字符串最左边位置为'-'。
来自华为的机试:
,(小声BB:用python,几句话的事)
上代码:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct bigIn{
int dig[1000];
int size;//大小
bigIn()
{
for(int i=0;i<1000;i++) dig[i]=0;
size=0;
}
void set(string str)
{
int L=str.size();
//cout<<L<<endl;
for(int i=L-1,j=0,t=0,c=1;i>=0;i--)//从后往前读。从前往后存。
{
t+=(str[i]-'0')*c;
c*=10;
j++;
if(j==4||i==0)
{
dig[size++]=t;
j=0;t=0;c=1;
}
}
}
void output()//从后往前读,从前往后输出。
{
//cout<<size-1<<endl;
for(int i=size-1;i>=0;i--)
{
if(i!=size-1)
{
printf("%04d",dig[i]);
}
else printf("%d",dig[i]);
}
printf("\n");
}
bigIn operator +(const bigIn &A) const{
bigIn ret;
int carry=0;
for(int i=0;i<A.size||i<size;i++)
{
int tmp=A.dig[i]+dig[i]+carry;
carry=tmp/10000;
tmp%=10000;
ret.dig[ret.size++]=tmp;
}
if(carry!=0)
{
ret.dig[ret.size++]=carry;//保存进位
}
return ret;
}
bigIn operator -(const bigIn &A) const{
bigIn ret;
int carry=0;
for(int i=0;i<A.size||i<size;i++)
{
int tmp=dig[i]-A.dig[i]+carry;
carry=tmp<0 ? -1:0;
tmp=(tmp+10000)%10000;
ret.dig[ret.size++]=tmp;
}
if(carry!=0)
{
ret.dig[ret.size++]=carry;//保存进位
}
return ret;
}
};
string str1,str2;
int main()
{
while(cin>>str1>>str2)
{
bigIn a,b,c;
int flag;//-2->全负数 一负一正(-1:前面负 1:后面负) 2->全正数
if(str1[0]=='-'&&str2[0]=='-')
flag=-2;
else if(str1[0]!='-'&&str2[0]!='-')
flag=2;
else if(str1[0]=='-') flag=-1;
else flag=1;
if(flag==2)
{
a.set(str1);b.set(str2);
c=a+b;c.output();
}
else if(flag==-2)
{
str1=str1.substr(1);
str2=str2.substr(1);
a.set(str1);b.set(str2);
c=a+b;
printf("-");c.output();
}
else if(flag==-1)
{
str1=str1.substr(1);
a.set(str1);b.set(str2);
c=b-a;c.output();
}
else
{
str2=str2.substr(1);
a.set(str1);b.set(str2);
c=a-b;c.output();
}
}
return 0;
}
其实乘也是同一个原理。也是
carry=tmp/10000;//(进位)
tmp%=10000;//去除进位部分
从某某大神那搞到了一个大数乘的模板,他这个是按位的。(其实可以多位一起)
string mul(string multiplied,string multiplier) { tmp = string(150,'0'); int carrier=0;//进位; int answer=0;//得数; int j = 0;int i = 0; for (i = 0; i < multiplied.length(); i++) { carrier = 0; for (j = 0; j < multiplier.length(); j++) { answer = ((multiplier.at(j)-'0')*(multiplied.at(i)-'0') + (tmp.at(i+j)-'0') + carrier )%10; carrier = ((multiplier.at(j)-'0')*(multiplied.at(i)-'0') + (tmp.at(i+j)-'0') + carrier )/10; tmp[i+j] = answer + '0'; } if (carrier) { tmp[i+j] = carrier + '0'; } } //tmp[i+j]='/0';//不知道这个是否有必要; tmp = tmp.substr(0,i+j); return tmp; }