本文為大大維原創,最早於博客園發表,轉載請注明出處!!!
一、概述
C/C++中的int類型能表示的范圍是-2E31-2E31–1。unsigned類型能表示的范圍是0-2E32–1,即 0-4294967295。所以,int和unsigned類型變量,都不能保存超過10位的整數。有時我們需要參與運算的數,可能會遠遠不止10 位,例如,可能需要保留小數點后面100位(比如求π的值),那么,即便使用能表示很大數值范圍的double變量,但是由於double變量只有64位,所以還是不可能達到精確到小數點后面100位這樣的精度。double變量的精度也不足以表示一個100位的整數。一般我們稱這種基本數據類型無法表示的整數為大數。如何表示和存放大數呢?在c語言下,我們可以用數組存放和表示大整數,一個數組元素,存放大數中的一位。而在c++中,使用標准庫的string類型,使得大數問題的計算更加實用(沒有最大值的限制),更加靈活(輸入更加簡潔方便),更加簡單(可以方便的處理小數之間的運算)。
二、算法原理簡單描述:
看如下大整數的加法運算:
answer每一位都是num1、num2和carry的和,因此,我們在輸入加數和被加數的string之后,可以將內容進行一次反轉,這樣,answer[i]=num1[i]+num2[i]+carry[i-1]。反轉的一個重要的原因是可以方便的將向前的進位和運算變為向后的進位運算,有利於充分發揮string的特點。在這里,我們可以使用<algorithm>頭文件下的reverse()函數方便的實現string的內容反轉。當運算完畢后,反轉回來即可。
當加入小數點后,我們就需要考慮一些額外的問題--小數點的位置問題,筆者在此采用了如下的策略:將輸入內容格式檢查之后(使用了cctpe頭文件),將一個數分為小數部分和整數部分,然后先運算小數部分,將得到的carry最后和整數部分一起運算,最后將兩部分的和拼接在一起。
對於大數的減法問題,基本上是大數加法的一個逆運算過程,筆者不在細講,看源代碼就可以很容易的理解。
三、程序代碼:

1 /* 2 大數的運算1--加法: 3 利用C++ string實現任意長度正小數、整數之間的加減法 4 作者:大大維 5 2017/5/5 6 */ 7 #include<iostream> 8 #include<string> 9 #include<cctype> 10 #include<algorithm> 11 using namespace std; 12 string sum(string,string,string,string); 13 string sub(string,string,string,string); 14 int main() 15 { 16 string num1,num2; 17 cout<<"Input num1 , num2:"<<endl; 18 cin>>num1>>num2; 19 string num11,num12,num21,num22; 20 //輸入檢查 21 //是否是小數的標志 22 bool num1Flag=false,num2Flag=false; 23 for(auto c:num1) 24 { 25 //由數字或者數字加一個.組成 26 if(!isdigit(c)||num1.empty()) 27 { 28 if(c=='.'&&!num1Flag) 29 { 30 num1Flag=true; 31 } 32 else 33 { 34 cout<<"num1: Please input correct form!!!"<<endl; 35 return 0; 36 } 37 } 38 } 39 for(auto c:num2) 40 { 41 if(!isdigit(c)||num2.empty()) 42 { 43 if(c=='.'&&!num2Flag) 44 { 45 num2Flag=true; 46 } 47 else 48 { 49 cout<<"num2: Please input correct form!!!"<<endl; 50 return 0; 51 } 52 } 53 } 54 55 //字符串分割{整數部分和小數部分) 56 if(num1Flag)//如果是小數 57 { 58 int i=0; 59 while(i!=num1.size()&&num1[i]!='.') 60 { 61 num11+=num1[i]; 62 ++i; 63 } 64 while(++i!=num1.size()) 65 { 66 num12+=num1[i]; 67 } 68 //用於.XXX或XXX.型輸入的控制 69 if(num11.empty()) 70 num11+='0'; 71 if(num12.empty()) 72 num12+='0'; 73 } 74 else//如果是整數 75 { 76 num11=num1; 77 num12+='0'; 78 } 79 if(num2Flag)//如果是小數 80 { 81 int i=0; 82 while(i!=num2.size()&&num2[i]!='.') 83 { 84 num21+=num2[i]; 85 ++i; 86 } 87 while(++i!=num2.size()) 88 { 89 num22+=num2[i]; 90 } 91 //用於.XXX或XXX.型輸入的控制 92 if(num21.empty()) 93 num21+='0'; 94 if(num22.empty()) 95 num22+='0'; 96 } 97 else//如果是整數str 98 { 99 num21=num2; 100 num22+='0'; 101 } 102 103 cout<<"The Sum result = "<<sum(num11,num12,num21,num22)<<endl; 104 cout<<"The Sub result = "<<sub(num11,num12,num21,num22)<<endl; 105 } 106 107 108 //加法 較長的整數部分 較長的小數部分 較短的整數部分 較短的小數部分 109 string sum(string strLong1,string strLong2,string strShort1,string strShort2) 110 { 111 //小數部分計算 112 if(strLong2.size()<strShort2.size()) 113 { 114 string strTemp=strLong2; 115 strLong2=strShort2; 116 strShort2=strTemp; 117 } 118 //補0 119 for(int i=strShort2.size(); i<strLong2.size(); ++i) 120 strShort2+='0'; 121 //反轉字符串 122 reverse(strLong2.begin(),strLong2.end()); 123 reverse(strShort2.begin(),strShort2.end()); 124 //小數部分進行加法計算 125 string strRes2(strLong2.size(),'0'); 126 int carry=0;//進位 127 for(int i=0; i!=strLong2.size(); ++i) 128 { 129 int a=strShort2[i]-'0',b=strLong2[i]-'0'; 130 a=a+b+carry; 131 carry=a/10; 132 strRes2[i]=(a%10)+'0'; 133 } 134 //反轉回來 135 reverse(strRes2.begin(),strRes2.end()); 136 137 138 //整數部分計算 139 if(strLong1.size()<strShort1.size()) 140 { 141 string strTemp=strLong1; 142 strLong1=strShort1; 143 strShort1=strTemp; 144 } 145 //反轉字符串 146 reverse(strLong1.begin(),strLong1.end()); 147 reverse(strShort1.begin(),strShort1.end()); 148 149 150 string strRes1(strLong1.size(),'0'); 151 for(int i=0; i!=strShort1.size(); ++i) 152 { 153 int a=strShort1[i]-'0',b=strLong1[i]-'0'; 154 a=a+b+carry; 155 carry=a/10; 156 strRes1[i]=(a%10)+'0'; 157 } 158 for(int i=strShort1.size(); i!=strLong1.size(); ++i) 159 { 160 int b=strLong1[i]-'0'; 161 b+=carry; 162 carry=b/10; 163 strRes1[i]=b%10+'0'; 164 } 165 if(carry) 166 { 167 strRes1+=(carry+'0'); 168 } 169 //反轉回來 170 reverse(strRes1.begin(),strRes1.end()); 171 172 173 //合並整數部分和小數部分 174 string strRes=strRes1+'.'+strRes2; 175 return strRes; 176 } 177 178 //減法 被減數的整數部分 被減數的小數部分 減數的整數部分 減數的小數部分 179 string sub(string strBjs1,string strBjs2,string strJs1,string strJs2) 180 { 181 //小數部分進行減法計算 182 int cntTemp=strBjs2.size()-strJs2.size(); 183 //補0 184 if(cntTemp<=0) 185 { 186 for(int i=cntTemp;i!=0;++i) 187 { 188 strBjs2+='0'; 189 } 190 } 191 else 192 { 193 for(int i=cntTemp;i!=0;--i) 194 { 195 strJs2+='0'; 196 } 197 } 198 199 //反轉字符串 200 reverse(strBjs2.begin(),strBjs2.end()); 201 reverse(strJs2.begin(),strJs2.end()); 202 string strRes2(strBjs2.size(),'0'); 203 int carry=0;//進位 204 for(int i=0; i!=strBjs2.size(); ++i) 205 { 206 int a=strBjs2[i]-'0',b=strJs2[i]-'0'; 207 a=a-b-carry; 208 if(a>=0) 209 { 210 carry=0; 211 strRes2[i]=a+'0'; 212 } 213 else 214 { 215 carry=1; 216 strRes2[i]=a+10+'0'; 217 } 218 } 219 //反轉回來 220 reverse(strRes2.begin(),strRes2.end()); 221 222 223 224 //整數部分進行減法計算 225 //反轉字符串 226 reverse(strBjs1.begin(),strBjs1.end()); 227 reverse(strJs1.begin(),strJs1.end()); 228 string strRes1(strBjs1.size(),'0'); 229 for(int i=0;i!=strJs1.size();++i) 230 { 231 int a=strBjs1[i]-'0',b=strJs1[i]-'0'; 232 a=a-b-carry; 233 if(a>=0) 234 { 235 carry=0; 236 strRes1[i]=a+'0'; 237 } 238 else 239 { 240 carry=1; 241 strRes1[i]=a+10+'0'; 242 } 243 } 244 for(int i=strJs1.size();i!=strBjs1.size();++i) 245 { 246 int a=strBjs1[i]-'0'; 247 a=a-carry; 248 if(a>=0) 249 { 250 carry=0; 251 strRes1[i]=a+'0'; 252 } 253 else 254 { 255 carry=1; 256 strRes1[i]=a+10+'0'; 257 } 258 } 259 if(carry)//此時除數比被除數大,結果為負數 260 { 261 return "*"; 262 } 263 //反轉回來 264 reverse(strRes1.begin(),strRes1.end()); 265 266 267 //清楚冗余0 268 string strTemp; 269 cntTemp=0; 270 for(int i=0;strRes1[i]=='0';++i)++cntTemp; 271 for(int i=cntTemp;i!=strRes1.size();++i) 272 strTemp+=strRes1[i]; 273 strRes1=strTemp; 274 //合並整數部分和小數部分 275 string strRes=strRes1+'.'+strRes2; 276 return strRes; 277 }
四、運行結果截圖:
說明1:此處有一定的容錯性,可以處理(.X或X.型的數據)
說明2:(*)表示結果為負數,不再處理
說明3:對輸出格式統一控制為小數類型