要求:科学记数法必须是(d e± i,e后不能省略+或-)运算符必须是(+、-、*、/、^,5种)
暂未处理有括号的运算式;字符串也不能有运算符和数字(包括 . 和e)之外的字符
步骤:先用正则表达式regex把字符串算式拆分成数和运算符,依次存放进容器vector,
然后按运算符优先级别先后计算出中间结果,最后计算代数和。
代码如下:
#include <iostream> #include <iomanip> #include <string> #include <vector> #include <regex> #include <cfloat> using namespace std; #define isSgn(s) (s=="+"?1:(s=="-"?2:(s=="*"?3:(s=="/"?4:(s=="^"?5:(s==""?1:0)))))) int Error=0; int regexSplit(string&, const string, vector<string>&, int=0); long double str2ld(string); string ld2str(long double); long double expSum(string); void outError(void); template<typename Type> void v_erase(vector<Type> &v, size_t pos) { //删除容器中指定第pos和pos+1个元素 if (pos+1>v.size()) return; vector<Type> tmp(v.begin()+pos+1,v.end()); while (v.size()>pos-1) v.pop_back(); for (auto t:tmp) v.push_back(t); vector<Type>().swap(tmp); //清空临时容器tmp } int main(void) { long double sum; string str = "-1+2*3+4/5-5.8e+1+1.9999999999999999984279*2^16383"; sum=expSum(str); if (Error==0) cout<<str<<"="<<endl<<setprecision(18)<<sum<<endl; else outError(); cout<<"long doube最大值DBL_MAX:"<<endl<<setprecision(18)<<LDBL_MAX; return 0; } long double expSum(string str) { long double sum=0; string reg("\\d+|\\d+\\.\\d+|(\\d+|\\d+\\.\\d+)e[+-]\\d+"); vector <string> v,vt; regexSplit(str,reg,v); regexSplit(str,reg,vt,-1); if (!(isdigit(str[0])||str[0]=='+'||str[0]=='-')) Error=1; //表达式错 for(auto t:vt) if (t.size()>1||!isSgn(t)) Error=2; //表达式错 for (int i=0;i<vt.size();i++) //vt间隔插入v v.insert(v.begin()+i*2,1,vt.at(i)); for (int i=1;i<v.size();i++) if(v.at(i)=="^"){ //幂指运算 v.at(i-1)=ld2str(pow(str2ld(v.at(i-1)),str2ld(v.at(i+1)))); if (v.at(i-1)=="inf") Error=3; //溢出,结果超出long double范围 if (v.at(i-1)=="nan") Error=4; //无意义,如负数的小数次方 if (v.at(i-1)=="inf"||v.at(i-1)=="nan") break; v_erase(v,i+1); i--; //位置前移1,解决如2^2^3这样的连续幂指运算 } for (int i=1;i<v.size();i++) //把所有x/n转换成x*(1/n) if(v.at(i)=="/") if (v.at(i+1)!="0"){ v.at(i+1)=ld2str(1/str2ld(v.at(i+1))); v.at(i)="*"; } else{ Error=5; //除0错 break; } for (int i=1;i<v.size();i++) if(v.at(i)=="*"){ v.at(i-1)=ld2str(str2ld(v.at(i-1))*str2ld(v.at(i+1))); v_erase(v,i+1); i--; //位置前移1,解决连乘运算 } for (int i=0;i<v.size();i++){ if(v.at(i)=="-"){ // 把所有x-n转换成x+(-n) v.at(i)="+"; v.at(i+1)="-"+v.at(i+1); } } for (int i=1;i<v.size();i=i+2) //求出算式的代数和 sum+=str2ld(v.at(i)); vector<string>().swap(v); //清空容器 vector<string>().swap(vt); return sum; } int regexSplit(string &str,const string str_reg,vector<string>&vect,int pos) { if (pos!=-1) pos=0; //pos=0 匹配到的位置,pos=-1匹配位置的前一字串 regex myPattern(str_reg); sregex_token_iterator it(str.begin(),str.end(),myPattern,pos); sregex_token_iterator end; for(;it!=end;++it) vect.push_back(*it); return vect.size(); //if 0 没有匹配到,else 匹配到的个数 } string ld2str(long double d) { string s; stringstream ss; ss<<setprecision(18)<<d; s=ss.str(); ss.clear(); return s; } long double str2ld(string s) { long double d; stringstream ss; ss<<s; ss>>setprecision(18)>>d; ss.clear(); return d; } void outError(void) { switch(Error){ case 1: case 2: cout<<"表达式错!"; break; case 3: cout<<"#INF错误!"; break; case 4: cout<<"#NAN错误!"; break; case 5: cout<<"#DIV/0错!"; break; } Error=0; }
运行结果:
-1+2*3+4/5-5.8e+1+1.9999999999999999984279*2^16383= 1.18973149535723177e+4932 long doube最大值DBL_MAX: 1.18973149535723177e+4932 -------------------------------- Process exited after 0.5967 seconds with return value 0 请按任意键继续. . .
顺带找到一个比较接近long double最大值的数:1.9999999999999999984279*2^16383
看来我的系统上long double型是12字节的,最大值应该是2^16384 -1
通常double型数字到 2^1024 就溢出了