高精度
这里写了关于高精度的加减乘除运算,前面三种都可用我们平时列式子,打草稿的思维写出来,对位相加,对位相减,错位相乘。但是除法就需要注意了,它的商很不好计算,不信的可以自己想一下思路再看下面,具体的除法思路在下面代码的注释中
1 #include"iostream" 2 #include"string" 3 using namespace std; 4 string add(string s1,string s2); 5 string operator- (string s1,string s2); 6 string operator* (string s1,string s2); 7 string operator/ (string s1,string s2); 8 void check(string &s); 9 int compare(string &s1,string &s2); 10 11 void check(string &s){ //去除前面多余的0 12 string s1 = ""; 13 int i = 0; 14 while(s[i++] == '0'); 15 i--; 16 while(s[i] != 0){ 17 s1 += s[i++]; 18 } 19 s = (s1 == "" ? "0" : s1); 20 } 21 22 int compare(string &s1,string &s2){ //比较两个数 23 int len1 = s1.length(); 24 int len2 = s2.length(); 25 if(len1 > len2){ 26 return 1; 27 } 28 else if(len1 < len2){ 29 return -1; 30 } 31 else if(s1 > s2){ 32 return 1; 33 } 34 else if(s1 < s2){ 35 return -1; 36 } 37 else{ 38 return 0; 39 } 40 } 41 string add(string s1,string s2){ //为了不影响+连接字符串,这里不重载+号运算符 42 if(s1[0] == '-'){ //第一个数为负,当作第二个数减第一个,这时不用判断另一个数是否为负,因为减法已经有处理负数的能力 43 string s3(&s1[1]); 44 return s2 - s3; 45 } 46 if(s2[0] == '-'){ //第二个数为负,当作第一个数减第二个 47 string s3(&s2[1]); 48 return s1 - s3; 49 } 50 int len1 = s1.length(); 51 int len2 = s2.length(); 52 int i = len1 - 1,j = len2 - 1,k = 0; 53 char c[10000] = {0}; 54 while(i >= 0 && j >= 0){ //从末尾开始对应相加 55 c[k++] = s1[i--] - '0' + s2[j--] - '0'; 56 } 57 while(i >= 0){ //加上剩下的s1 58 c[k++] = s1[i--] - '0'; 59 } 60 while(j >= 0){ //加上剩下的s2 61 c[k++] = s2[j--] - '0'; 62 } 63 c[k] = 0; //末尾标记 64 for(int i = 0;i <= k;i++){ //进位 65 if(c[i] > 9){ 66 c[i] -= 10; 67 c[i + 1]++; 68 } 69 } 70 for(int i = 0;i <= k;i++){ //转换为asc字符 71 c[i] += '0'; 72 } 73 string s3(c); //用c创建string 74 string s4(s3.rbegin(),s3.rend()); //再逆序创建 75 check(s4); //去首位的0 76 return s4; 77 } 78 string operator- (string s1,string s2){ 79 int isfushu = 0; 80 if(s1[0] == '-' && s2[0] != '-'){ //被减数为负数,相当于加法 81 string s3(s1.begin() + 1,s1.end()); 82 return "-" + add(s3,s2); 83 } 84 if(s2[0] == '-' && s1[0] != '-'){ //减数为负,也相当于加法 85 string s3(s2.begin() + 1,s2.end()); 86 return add(s3,s1); 87 } 88 if(s2[0] == '-' && s1[0] == '-'){ //都为负,相当于是减数与被减数交换位置 89 string s3(s1.begin() + 1,s1.end()); 90 string s4(s2.begin() + 1,s2.end()); 91 s1 = s4; 92 s2 = s3; 93 } 94 if(compare(s1,s2) < 0){ //如果s1 < s2 交换位置,并标记为负数 95 isfushu = 1; 96 string s3 = s1; 97 s1 = s2; 98 s2 = s3; 99 } 100 int len1 = s1.length(); 101 int len2 = s2.length(); 102 int i = len1 - 1,j = len2 - 1; 103 while(i >= 0 && j >= 0){ //从末尾开始对应相减 104 s1[i--] -= (s2[j--] - '0'); 105 } 106 for(int i = len1 - 1;i > 0;i--){ //借位 107 if(s1[i] < '0'){ 108 s1[i - 1]--; 109 s1[i] += 10; 110 } 111 } 112 check(s1); 113 if(isfushu){ //负数前面加上负号 114 s1 = "-" + s1; 115 } 116 return s1; 117 } 118 119 string operator* (string s1,string s2){ 120 int isfushu = 0; 121 if(s1[0] == '-' && s2[0] != '-') { //有一个为负数则为负数 122 isfushu = 1; 123 s1 = string(&s1[1]); 124 } 125 if(s2[0] == '-' && s1[0] != '-'){ 126 isfushu = 1; 127 s2 = string(&s2[1]); 128 } 129 if(s2[0] == '-' && s1[0] == '-'){ //全为负数,结果为正 130 s1 = string(&s1[1]); 131 s2 = string(&s2[1]); 132 } 133 int len1 = s1.length(); 134 int len2 = s2.length(); 135 char c[10000] = {0}; //临时数组 136 for(int i = len1 - 1;i >= 0;i--){ //从最低位开始计算 137 for(int j = len2 - 1;j >= 0;j--){ 138 int ge = (s1[i] - 48) * (s2[j] - 48); //两位相乘结果 139 int gew = len1 + len2 - i - j - 2; //当前个位的下标 140 c[gew] += ge % 10; //加上个位 141 c[gew + 1] += ge / 10 % 10; //加上十位 142 } 143 int k = 0; 144 while(k < len1 + len2 - 1){ //进位,每一位数乘完每一个数后就进位,char最大为127,这里最大为9+9+9=27,保证了在最大值内,不会出错 145 //cout<<(int)c[k]<<endl; 146 c[k + 1] += (c[k] / 10); 147 c[k] = c[k] % 10; 148 ++k; 149 } 150 } 151 //char 型数组的进位不能放这里,int 型数组可以 152 for(int i = 0;i < len1 + len2;i++){ //转换为asc字符 153 c[i] += 48; 154 } 155 string s3(c); 156 string s4(s3.rbegin(),s3.rend()); 157 check(s4); 158 if(isfushu){ 159 return "-" + s4; 160 } 161 return s4; //返回逆序 162 } 163 164 int jianfa(string &s1,string &s2){ //用于除法的减法,通过减的次数来求商,这个减法不能当作一般的减法使用 165 int len1 = s1.length(); 166 int len2 = s2.length(); 167 int i,j,count = 0; 168 while(true){ 169 i = len1 - 1; 170 j = len2 - 1; 171 string temp = s1; //临时保存被减数 172 while(i >= 0 && j >= 0){ //从末尾开始对应相减 173 s1[i--] -= (s2[j--] - '0'); 174 } 175 for(int i = len1 - 1;i > 0;i--){ //借位 176 if(s1[i] < '0'){ 177 s1[i - 1]--; 178 s1[i] += 10; 179 } 180 } 181 if(s1[0] < '0'){ //首位都被借完了,停止相减,并恢复被减数 182 s1 = temp; 183 break; 184 } 185 186 count++; 187 } 188 return count; 189 } 190 191 string operator/ (string s1,string s2){ 192 int jianfa(string &s1,string &s2); 193 int isfushu = 0; 194 if(s1[0] == '-' && s2[0] != '-') { //有一个为负数则为负数 195 isfushu = 1; 196 s1 = string(&s1[1]); 197 } 198 if(s2[0] == '-' && s1[0] != '-'){ 199 isfushu = 1; 200 s2 = string(&s2[1]); 201 } 202 if(s2[0] == '-' && s1[0] == '-'){ //全为负数,结果为正 203 s1 = string(&s1[1]); 204 s2 = string(&s2[1]); 205 } 206 int len1 = s1.length(); 207 int len2 = s2.length(); 208 char chushu[10000] = {0}; //临时保存除数,这里的除数是指扩大10*n倍后的除数. 209 string s4 = ""; //保存结果 210 for(int i = len1 - 1;i >= len2 - 1;i--){ //这里i表示除数的位数,它的位数在len2~~~len1之间,如12345/45,那么除数分别为45000,4500,450,45 211 for(int j = 0;j <= i;j++){ //修改除数 212 if(j < len2){ 213 chushu[j] = s2[j]; //先存上本身除数 214 } 215 else{ 216 chushu[j] = '0'; //后面的用0填充 217 } 218 } 219 chushu[i + 1] = 0; //结束标志 220 string s3(chushu); //转为string 221 s4 += jianfa(s1,s3) + 48; //被除数 - 除数,直到不够减为止,减的次数就是该位的商,如125/5:125-500=0次,125-50=2次,25-5=5次,结束,那么商为25 222 } 223 check(s1); //余数 224 check(s4); //商 225 if(isfushu){ 226 if(s1[0] != '0'){ 227 s1 = '-' + s1; 228 } 229 if(s4[0] != '0'){ 230 s4 = '-' + s4; 231 } 232 } 233 //cout<<"余数:"<<s1<<endl; 234 return s4; 235 } 236 237 int main(){ 238 string s1,s2; 239 //cout<<add(s1,s2)<<endl; 240 cin>>s1>>s2; 241 cout<<add(s1,s2)<<endl; 242 cout<<s1 - s2<<endl; 243 cout<<s1 * s2<<endl; 244 cout<<s1 / s2<<endl; 245 return 0; 246 }
BY oleolema