高精度

 这里写了关于高精度的加减乘除运算,前面三种都可用我们平时列式子,打草稿的思维写出来,对位相加,对位相减,错位相乘。但是除法就需要注意了,它的商很不好计算,不信的可以自己想一下思路再看下面,具体的除法思路在下面代码的注释中

 

 

  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 }

 

posted @ 2018-06-14 01:05  oleolema  阅读(343)  评论(0编辑  收藏  举报