嗯,作者在咕咕咕了整整一个月后又来写 A + B Problem 了……
一看题目,发现 |a| , |b| <= 1e9 , 而且 a 和 b 还都是整数,所以我们自然而然地想到了要用高精度来计算啦 [aru_7]
然而作者太菜了不会写高精度 QAQ,所以作者就用 bitset 来实现了一个 512 位整数以及对应的加法运算,加法运算的原理,就是计算机中加法器的原理。
具体的来讲,就是 a + b = (a xor b) + (a and b) * 2,其中乘以二的操作可以用左移来表示,也就是说这样的加法可以全部由位运算来实现,只不过外面要包一层循环。
该结论证明:
首先,我们观察以下算式:(其中 ^ 表示异或,数字皆为二进制)
0 ^ 0 = 0, 0 & 0 = 0, 0 + 0 = 00
1 ^ 0 = 1, 1 & 0 = 0, 1 + 0 = 01
0 ^ 1 = 1, 0 & 1 = 0, 0 + 1 = 01
1 ^ 1 = 0, 1 & 1 = 0, 1 + 1 = 10
不难发现,任意两个一位的二进制数 a 和 b 相加所得的结果一定是 (a & b) * 2 + (a ^ b)
因此,我们可以得到:
于是得证。
还有一个问题,就是如何将读入的十进制数转为二进制,以及将二进制转为十进制并输出……这个问题我们用满八减三法和满五加三法来解决。具体证明我也不太会,可以百度一下 [aru_25]
所以,这个问题就可以被“圆满”的解决了!下面贴上代码:
#include<bits/stdc++.h> /* * Code from vgakbzc */ typedef std::bitset<512> int512; char buf[1007]; int512 StrToBCD(char* s){ int len=strlen(s); int cur=0; int512 res; for(int i=len-1;i>=0;i--,cur+=4){ // String to bcd code int x=s[i]-'0'; res[cur+0]=bool(x&1); res[cur+1]=bool(x&2); res[cur+2]=bool(x&4); res[cur+3]=bool(x&8); } return res; } int512 BCDToBIN(int512 bcd){ // bcd code to binary std::bitset<1024> tmp; tmp.reset(); for(int i=512;i<1024;i++){ tmp[i]=bcd[i-512]; } for(int i=0;i<512;i++){ tmp>>=1; for(int j=512;j<1024;j+=4){ int p=tmp[j]+tmp[j+1]*2+tmp[j+2]*4+tmp[j+3]*8; // 满八减三 if(p>=8){ p-=3; tmp[j+0]=bool(p&1); tmp[j+1]=bool(p&2); tmp[j+2]=bool(p&4); tmp[j+3]=bool(p&8); } } } for(int i=0;i<512;i++){ bcd[i]=tmp[i]; } return bcd; } void BCDToStr(int512 bcd,char* buf){ // bcd code to string memset(buf,0,sizeof(buf)); for(int i=0;i<512;i+=4){ buf[i/4]='0'+bcd[i]+bcd[i+1]*2+bcd[i+2]*4+bcd[i+3]*8; } for(int i=127;i>=0;i--){ if(buf[i]!='0')break; else buf[i]=0; } int len=strlen(buf); std::reverse(buf,buf+len); } int512 BINToBCD(int512 bin){ // binary to bcd code std::bitset<1024> tmp; // 由于数据范围,这里假设 bcd 码不超过 512 位。实际上是有可能超过 512 位的 tmp.reset(); for(int i=0;i<512;i++){ tmp[i]=bin[i]; } for(int i=0;i<512;i++){ for(int j=512;j<1024;j+=4){ if(tmp[j+3]||tmp[j+2]&&(tmp[j+1]||tmp[j])){ // 满五加三,写法与上面不同 std::bitset<4>res; // 3 -> 0011 res[0]=tmp[j]^1; res[1]=tmp[j]&1; res[2]=(res[1]&tmp[j+1])||(tmp[j+1]&1)||(1&res[1]); res[1]=tmp[j+1]^1^res[1]; res[3]=(res[2]&tmp[j+2])||(tmp[j+2]&0)||(0&res[2]); res[2]=tmp[j+2]^0^res[2]; res[3]=tmp[j+3]^0^res[3]; tmp[j]=res[0],tmp[j+1]=res[1],tmp[j+2]=res[2],tmp[j+3]=res[3]; } } tmp<<=1; } for(int i=512;i<1024;i++){ bin[i-512]=tmp[i]; } return bin; } int512 operator+(int512 a,int512 b){ // 加法,很简短 AwA while(b.any()){ int512 t1=a^b,t2=a&b; a=t1,b=t2<<1; } return a; } std::istream& operator>>(std::istream& in,int512 &a){ // 封装输入 in>>buf; a=BCDToBIN(StrToBCD(buf[0]=='-'?buf+1:buf)); if(buf[0]=='-'){ int i=0; while(a[i]==0){ i++; } i++; while(i<512){ a[i]=!a[i]; i++; } } return in; } std::ostream& operator<<(std::ostream& out,int512 a){ //·封装输出 if(a[511]==1){ out<<'-'; int i=0; while(a[i]==0){ i++; } i++; while(i<512){ a[i]=!a[i]; i++; } } BCDToStr(BINToBCD(a),buf); if(strlen(buf)==0){ buf[0]='0'; } out<<buf; return out; } int main(){ // 主函数 int512 a,b; std::cin>>a>>b; std::cout<<a+b; }
这次代码可比上次长多了……真的是小题大做吧 [aru_39]
PS:站长已修改此博文
本文作者为vgakbzc,转载请注明。
博主厉害,我都不会[emoji_38]
@光阴似箭我也没看懂呢 [aru_19]