学习C++后做的第一个第一个小项目,参考了网上的一些些好的代码,任意进制中A和a看作是一个数,所以最高36进制,不过这个小地方改成10+26+26进制也很好改。
首先实现十进制长整数加法和减法,既然是长整数,最终决定可以使用string字符串作为储存长整数的格式
加法
string jia(string a, string b) { string str1 = a; string str2 = b; int len = max(str1.size(), str2.size()); string result; reverse(str1.begin(), str1.end()); reverse(str2.begin(), str2.end()); int jinwei = 0; for (int i = 0; i < len; ++i) { int str1_i = i < str1.size() ? str1[i] - '0' : 0; int str2_i = i < str2.size() ? str2[i] - '0' : 0; int val = (str1_i + str2_i + jinwei) % 10; jinwei = (str1_i + str2_i + jinwei) / 10; result.insert(result.begin(), val + '0'); } if (jinwei == 1) result.insert(result.begin(), '1'); if (result[0] == '0') result[0] = ' '; return result; }
减法
string jian(string a,string b) { string s1 = a; string s2 = b; if(s1==s2) { return "0"; } string s3; bool flag=false; if(s1.length()<s2.length() || (s1.length()==s2.length() && s1<s2)) { std::string s=s1; s1=s2; s2=s; flag=true; } else { s3=""; } while(s2.length()<s1.length()) { s2="0" + s2; } int k,down=0; for(int i=s1.length()-1; i>=0; i--) { k=s1[i] -s2[i] +down; if(k<0) { down=-1; k=10+k; } else { down=0; } s3=(char)('0' + k) + s3; } k=0; while(s3[k]=='0' ) { k++; } s3=s3.substr(k); if(flag) s3="-"+s3; return s3; }
随后是根据输入的进制将输入的字符串转化为十进制,其中使用加法的循环构造了字符串乘法运算,估计效率不会很高:
string otherToDec(int a, string str) { int tmp = 0; string c = to_string(1); string c_ = to_string(1); string result(1, '0'); for (int i = str.size() - 1; i >= 0; i--) { int x = 0; bool fling = true; bool ori = true; string tmp_(1, '0'); if (str[i] >= 'A' && str[i] <= 'Z'){ x = str[i] - 'A' + 10; ori = false; } else if (str[i] >= 'a' && str[i] <= 'z'){ x = str[i] - 'a' + 10; ori = false; } else if (str[i] >= '1' && str[i] <= '9'){ x = str[i] - '0'; ori = false; } else if (str[i] == '0' && ori) { fling = false; if(i == str.size() - 1) ; else { result.insert(result.begin(), '0'); } } if (fling) { for (int j = 0 ; j < x; j++) tmp_ = jia(tmp_, c); //tmp += x*c result = jia(result, tmp_); } for (int k = 0 ; k < a-1; k++) c_ = jia(c_,c); //c =c*a c = c_; } return result; }
随后进行字符串的加减运算后再把运算后的十进制字符串转换为任意进制,因为这里要用到取余的方法,因此又引入了一个字符串除法
string chu(string a,string b) { if(b.length()==1&&b.at(0)==48) return "error"; long int i,j; string c1,c2,d,e; if(judge(a,b)==0) return "1"; if(judge(a,b)==-1) { return "0"; } c1=dezero(a); c2=dezero(b); d=""; e=""; for(i=0;i<c1.length();i++) { j=0; d=d+c1.at(i); d=dezero(d); while(judge(d,b)>=0) { d=jian(d,b); d=dezero(d); j++; } e=e+"0"; e.at(i)=j; } for(i=0;i<e.length();i++) { if(e.at(i)>=10) e.at(i)+=87; if(e.at(i)<10) e.at(i)+=48; } e=dezero(e); return e; } //其中需要的judge和dezero函数如下 string dezero(string a) { long int i; for(i=0;i<a.length();i++) { if(a.at(i)>48) break; } if(i==a.length()) return "0"; a.erase(0,i); return a; } int judge(string a,string b) { if(a.length()>b.length()) return 1; if(a.length()<b.length()) return -1; long int i; for(i=0;i<a.length();i++) { if(a.at(i)>b.at(i)) return 1; if(a.at(i)<b.at(i)) return -1; } return 0; }
进制转换的具体代码如下,那个一大串else if写的很蠢,但是string中每一个元素是char*类型,对于12,13这样的结果又不好直接转成char(写这个的时候想到或许可以用转十进制的思路写),然后觉得可以考虑保存为char[]来写,不过脑子笨就先搞成这样了,代码肯定还有很多优化空间。
string decToOther(string str, int b) { int i = 0; string re_; //char s[1000] = {'0'}; while (str != "0") { string temp; string yushu; temp = chu(str, to_string(b)); //temp = str/b string tmp_ = temp; for(int i = 0; i<(b-1); i++) temp = jia(temp,tmp_) ;//temp = (temp)*b yushu = jian(str, temp); //yushu = str-tmp if (tmp_ == "0"){ yushu = str; } //char *yushu_=(char*)yushu.data(); if(yushu == "1" || yushu == "2"|| yushu == "3"|| yushu == "4"|| yushu == "5" || yushu == "6"|| yushu == "7"|| yushu == "8"|| yushu == "9" || yushu == "0" ) re_ = yushu + re_; else if (yushu == "10") re_ = "A" + re_;else if (yushu == "11") re_ = "B" + re_; else if (yushu == "12") re_ = "C" + re_;else if (yushu == "13") re_ = "D" + re_; else if (yushu == "14") re_ = "E" + re_;else if (yushu == "15") re_ = "F" + re_; else if (yushu == "16") re_ = "G" + re_;else if (yushu == "17") re_ = "H" + re_; else if (yushu == "18") re_ = "I" + re_;else if (yushu == "19") re_ = "J" + re_; else if (yushu == "20") re_ = "K" + re_;else if (yushu == "21") re_ = "L" + re_; else if (yushu == "22") re_ = "M" + re_;else if (yushu == "23") re_ = "N" + re_; else if (yushu == "24") re_ = "O" + re_;else if (yushu == "25") re_ = "P" + re_; else if (yushu == "26") re_ = "Q" + re_;else if (yushu == "27") re_ = "R" + re_; else if (yushu == "28") re_ = "S" + re_;else if (yushu == "29") re_ = "T" + re_; else if (yushu == "30") re_ = "U" + re_;else if (yushu == "31") re_ = "V" + re_; else if (yushu == "32") re_ = "W" + re_;else if (yushu == "33") re_ = "X" + re_; else if (yushu == "34") re_ = "Y" + re_;else if (yushu == "35") re_ = "Z" + re_; str = tmp_; i++; } return re_; }
由于运算过程可能会出现前面带正负号的情况,或者是有0在开头的情况,下面的代码是具体的运算过程,其中jinzhi_in和jinzhi_out分别是输入的进制和准备输出的进制:
string yunsuan(string a, string b ,int jinzhi_in, int jinzhi_out) { string re_; bool eq = false; bool ng = false; if (a[0] == '-'){ a.erase(0,1); //const char* p = a.data(); a = otherToDec(jinzhi_in, a, 10); if (b[0] == '-'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); re_ = jia(a, b); re_.insert(re_.begin(), '-'); } else if (b[0] == '+'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); if (a == b) eq = true; re_ = jian(b, a); } else { b = otherToDec(jinzhi_in, b, 10); re_ = jian(b, a); } } else if (a[0] == '+'){ a.erase(0, 1); a = otherToDec(jinzhi_in, a, 10); if (b[0] == '-'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); re_ = jian(a, b); if (a == b) eq = true; } else if (b[0] == '+'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); re_ = jia(a, b); } else{ b = otherToDec(jinzhi_in, b, 10); re_ = jia(a, b); } } else{ a = otherToDec(jinzhi_in, a, 10); if (b[0] == '-'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); re_ = jian(a, b); } else if (b[0] == '+'){ b.erase(0, 1); b = otherToDec(jinzhi_in, b, 10); re_ = jia(a, b); } else { b = otherToDec(jinzhi_in, b, 10); re_ = jia(a, b); } } if (re_[0] == '-') { re_.erase(0,1); ng = true; } re_ = decToOther(re_, jinzhi_out); if (eq) re_ = '0'; if (ng) re_.insert(re_.begin(), '-'); return re_; }
最后是int main()主函数,采用的是文件读取的方法
int main() { ifstream fp; string a; //第一个长整数 string b; //第二个长整数 string c; //运算结果 int jinzhi_in; //输入进制 int jinzhi_out; //输出进制 fp.open("./data.txt",std::ios::in); if(!fp.is_open()){ cout<<"打开文件失败!!\n"<<endl;; return 1; } fp>>jinzhi_in>>jinzhi_out>>a>>b>>c; while ( jinzhi_in < 2 || jinzhi_in > 36 || jinzhi_out < 2 || jinzhi_out > 36)//检验输入是否正确 { cout << "请输入一个在2-36之间的整数" << endl; return 1; } while (panduan(a, jinzhi_in) || panduan(b, jinzhi_in))//检验输入是否正确 { cout << "输入字符串与进制不符!!" << endl; return 1; } string re_ = yunsuan(a,b,jinzhi_in,jinzhi_out); cout << re_ << endl; if (re_ == c) cout << "right" << endl; //system("pause"); return 0; }
哦还忘了一个判断输入是否正确的panduan函数,代码如下
bool panduan(string x, int y) { int len = x.size(); for (int i = 0; i < len; ++i) { int temp = (int)x[i]; int thre_1 = y - 10 + 97; //小写字母 int thre_2 = y - 10 + 65; //大写字母 if (i == 0){ if (x[i] == '+' || x[i] == '-' || (temp >= 48 && temp <= 57)) continue; else if (y > 10){ if ((temp >= 48 && temp <= 57) || (temp >= 97 && temp <= thre_1) || (temp >= 65 && temp <= thre_2)) continue; else ; } else { return 1; break; } } else{ if (y <= 10) { if (temp >= 48 && temp <= 57) continue; else { return 1; break; } } else if (y > 10) { if (temp >= 48 && temp <= 57) continue; else if (temp >= 97 && temp <= thre_1) continue; else if (temp >= 65 && temp <= thre_2) continue; else { return 1; break; } } } } return 0; }