表达式计算器

#include<bits/stdc++.h>
using namespace std;
enum Atom_type{NUMBER=1,LETTER=2,OPERATOR=3};
const int MAX_PARA=20;
int sign[128],prio[128],n_para;
vector<double> para_list_all[MAX_PARA];
//double para_list[MAX_PARA];
vector<string> parameters;
int gcd(int n,int m){
    if(n<0)n=-n;
    if(m<0)m=-m;
    while(m){
        n=n%m;
        swap(n,m);
    }
    return n;
}
struct Mocular{
    pair<int,int> coef;
    int cnt_pow[MAX_PARA];
    Mocular(){
        coef.first=coef.second=0;
        memset(cnt_pow,0,sizeof cnt_pow);
    }
    Mocular(const Mocular &a){
        coef=a.coef;
        for(int i=0;i<n_para;++i)cnt_pow[i]=a.cnt_pow[i];
    }
    Mocular(int n){
        coef={1,1};
        memset(cnt_pow,0,sizeof cnt_pow);
        if(n%10==NUMBER)coef={n/10,1};
        else cnt_pow[n/10]++;
    }
    void reduce(){
        int n_gcd=gcd(coef.first,coef.second);
        if(n_gcd){
            coef.first/=n_gcd;
            coef.second/=n_gcd;
        }
        if(coef.second<0){
            coef.first*=(-1);
            coef.second*=(-1);
        }
    }
    Mocular operator * (const Mocular &a){
        Mocular ret(*this);
        ret.coef.first*=a.coef.first;
        ret.coef.second*=a.coef.second;
        for(int i=0;i<n_para;++i)ret.cnt_pow[i]+=a.cnt_pow[i];
        ret.reduce();
        return ret;
    }
    Mocular operator / (const Mocular &a){
        Mocular ret(*this);
        ret.coef.first*=a.coef.second;
        ret.coef.second*=a.coef.first;
        for(int i=0;i<n_para;++i)ret.cnt_pow[i]-=a.cnt_pow[i];
        ret.reduce();
        return ret;
    }
    bool operator == (const Mocular &a){
        bool flag=true;
        for(int i=0;i<n_para;++i)
            if(cnt_pow[i]!=a.cnt_pow[i])flag=false;
        return flag;
    }
    void print(){
        int a=coef.first,b=coef.second;
        if(a==0)return;
        if(a>0)cout<<'+';
        else{
            cout<<'-';
            a=-a;
        }
        cout<<" ";
        if(a!=1&&b==1)cout<<a<<" ";
        else if(b!=1)cout<<a<<"/"<<b<<" ";
        bool flag=true;
        for(int i=0;i<n_para;++i)
            if(cnt_pow[i]){
                cout<<parameters[i];
                if(cnt_pow[i]!=1)cout<<'^'<<cnt_pow[i];
                cout<<" ";
                flag=false;
            }
        if(flag&&a==1&&b==1)cout<<"1 ";
    }
};
struct Expression{
    vector<Mocular> exp;
    Expression(){exp.clear();}
    Expression(const Expression &a){
        exp.clear();
        for(auto &x: a.exp)exp.emplace_back(x);
    }
    Expression(const Mocular &a){
        exp.clear();
        exp.emplace_back(a);
    }
    Expression operator + (const Expression &a){
        Expression ret(*this);
        for(auto &x: a.exp){
            bool flag=true;
            for(auto &y: ret.exp)
                if(y==x){
                    y.coef.first=y.coef.first*x.coef.second+y.coef.second*x.coef.first;
                    y.coef.second*=x.coef.second;
                    y.reduce();
                    flag=false;
                    break;
                }
            if(flag)ret.exp.push_back(x);
        }
        return ret;
    }
    Expression operator - (const Expression &a){
        Expression ret(a);
        for(auto &x: ret.exp)x.coef.first*=(-1);
        return *this+ret;
    }
    Expression operator * (const Expression &a){
        Expression ret;
        for(auto &x: exp)
            for(auto &y: a.exp)
                ret=ret+Expression(x*y);
        return ret;
    }
    Expression operator / (const Expression &a){
        Expression ret;
        for(auto &x: exp)
            ret=ret+Expression(x/a.exp[0]);
        return ret;
    }
    Expression power(int n){
        Expression ret(Mocular(11)),a(*this);
        if(n==0)return ret;
        while(n){
            if(n&1)ret=ret*a;
            a=a*a;
            n>>=1;
        }
        return ret;
    }
    void print(){
        for(auto &x: exp)x.print();
        cout<<endl;
    }
};

void init(){
    for(int i=1;i<128;++i)sign[i]=LETTER;
    for(int i='0';i<='9';++i)sign[i]=NUMBER;
    sign['.']=NUMBER;
    sign[0]=sign['+']=sign['-']=sign['*']=sign['/']=sign['^']=sign['(']=sign[')']=OPERATOR;
    prio['+']=prio['-']=1;
    prio['*']=prio['/']=2;
    prio['^']=3;
}
bool format(string &s,vector<int> &v){
    string tps,rts;
    v.clear();
    //formating s to a standard expression as well as detecting all errors
    if(sign[s[0]]==OPERATOR){
        switch(s[0]){
            case '+':s.erase(s.begin());break;
            case '-':s.insert(s.begin(),'0');break;
            case '*':case '/':case '^':case ')':return false;
            default:break;
        }
    }
    for(int i=0,n_b=0;i<s.size();){
        switch(sign[s[i]]){
            case NUMBER:
                if(rts.size()&&rts.back()==')')return false;
                for(;sign[s[i]]==NUMBER;++i)rts+=s[i];
                break;
            case LETTER:
                if(rts.size()&&rts.back()==')')return false;
                if(rts.size()&&sign[rts.back()]==NUMBER)rts+='*';
                tps.clear();
                if(s[i]=='['){
                    for(;i<s.size();++i){
                        rts+=s[i],tps+=s[i];
                        if(s[i]==']')break;
                    }
                    if(i==(int)s.size())return false;
                    else i++;
                }else for(;sign[s[i]]!=OPERATOR;++i)rts+=s[i],tps+=s[i];
                parameters.emplace_back(tps);
                break;
            case OPERATOR:
                if(s[i]=='(')n_b++;
                else if(s[i]==')')n_b--;
                if(n_b<0)return false;
                if(sign[rts.back()]==OPERATOR){
                    switch(s[i]){
                        case '+':case '-':
                            if(rts.back()!='('&&rts.back()!=')')return false;
                            if(rts.back()=='(')rts+='0';
                            break;
                        case '*':case '/':case '^':if(rts.back()!=')')return false;break;
                        case '(':if(rts.back()==')')rts+='*';break;
                        case ')':
                             if(rts.back()=='(')rts.pop_back();
                             else if(rts.back()!=')')return false;
                             break;
                    }
                }else if(s[i]=='(')rts+='*';
                rts+=s[i++];
                break;
        }
    }
    if(sign[rts.back()]==OPERATOR&&rts.back()!=')')return false;
    s=rts;
    //prepare parameters
    sort(parameters.begin(),parameters.end());
    n_para=unique(parameters.begin(),parameters.end())-parameters.begin();
    parameters.resize(n_para);
    //to code
    for(int i=0,n;i<s.size();){
        switch(sign[s[i]]){
            case NUMBER:
                for(n=0;sign[s[i]]==NUMBER;++i)
                    n=n*10+s[i]-'0';
                v.push_back(n*10+NUMBER);
                break;
            case LETTER:
                tps.clear();
                if(s[i]=='['){
                    for(;i<s.size();++i){
                        tps+=s[i];
                        if(s[i]==']')break;
                    }
                    i++;
                }else for(;sign[s[i]]!=OPERATOR;++i)tps+=s[i];
                n=lower_bound(parameters.begin(),parameters.end(),tps)-parameters.begin();
                v.push_back(n*10+LETTER);
                break;
            case OPERATOR:
                n=s[i++];
                v.push_back(n*10+OPERATOR);
                break;
        }
    }
    return true;
}
void RPN(vector<int> &v){
    vector<int> v1,v2;
    for(auto &x: v){
        switch(x%10){
            case NUMBER:
            case LETTER:
                v2.push_back(x);
                break;
            case OPERATOR:
                if(char(x/10)=='(')v1.push_back(x);
                else if(char(x/10)==')'){
                    while(char(v1.back()/10)!='('){
                        v2.push_back(v1.back());
                        v1.pop_back();
                    }
                    v1.pop_back();
                }else if(v1.empty())v1.push_back(x);
                else if(prio[v1.back()/10]<prio[x/10])v1.push_back(x);
                else{
                    while(!v1.empty()&&prio[v1.back()/10]>=prio[x/10]){
                        v2.push_back(v1.back());
                        v1.pop_back();
                    }
                    v1.push_back(x);
                }
                break;
        }
    }
    while(!v1.empty()){
        v2.push_back(v1.back());
        v1.pop_back();
    }
    v=v2;
}
void simplificate(vector<int> &v){
    vector<Expression> v1;
    Expression t1,t2;
    for(auto &x: v){
        switch(x%10){
            case NUMBER:
            case LETTER:
                v1.emplace_back(Mocular(x));
                break;
            case OPERATOR:
                t2=v1.back();v1.pop_back();
                t1=v1.back();v1.pop_back();
                switch(char(x/10)){
                    case '+':v1.push_back(t1+t2);break;
                    case '-':v1.push_back(t1-t2);break;
                    case '*':v1.push_back(t1*t2);break;
                    case '/':v1.push_back(t1/t2);break;
                    case '^':v1.push_back(t1.power(t2.exp[0].coef.first));break;
                }
                break;
        }
    }
    v1[0].print();
}
void calculate(vector<int> &v,vector<double> &para_list){
    vector<double> v1;
    double t1,t2;
    for(auto &x: v){
        switch(x%10){
            case NUMBER:
                v1.emplace_back(double(x/10));
                break;
            case LETTER:
                v1.emplace_back(para_list[x/10]);
                break;
            case OPERATOR:
                t2=v1.back();v1.pop_back();
                t1=v1.back();v1.pop_back();
                switch(char(x/10)){
                    case '+':v1.push_back(t1+t2);break;
                    case '-':v1.push_back(t1-t2);break;
                    case '*':v1.push_back(t1*t2);break;
                    case '/':v1.push_back(t1/t2);break;
                    case '^':v1.push_back(pow(t1,t2));break;
                }
                break;
        }
    }
    cout<<v1[0]<<endl;
}

char get_num_char(string &s){//for get_num()
    char _head=s[0];
    if((_head>='0'&&_head<='9')||_head=='-'||_head=='+'||_head=='.'||_head=='e'||_head=='E'){
        s.erase(s.begin());
        return _head;
    }else return 0;
}
double get_num_double(string &s){
    int figure=0,power=0,fixed=0,sig_figure=1,sig_power=1;
    bool power_mode=false,exist_error=false;
    char ch;
    double ret;
    while(ch=get_num_char(s)){
        if(ch=='-'&&!power_mode)sig_figure=-1;
        else if(ch=='-'&&power_mode)sig_power=-1;
        else if(ch=='+'&&!power_mode)sig_power=1;
        else if(ch=='+'&&power_mode)sig_power=1;
        else if(ch>='0'&&ch<='9'&&!power_mode)figure=figure*10+ch-'0';
        else if(ch>='0'&&ch<='9'&&power_mode)power=power*10+ch-'0';
        else if(ch=='.'&&!power_mode&&fixed==0){
        while(s[fixed]>='0'&&s[fixed]<='9')fixed++;
        }else if(tolower(ch)=='e'&&!power_mode&&power==0)power_mode=true;
        else{
            exist_error=true;
            break;
        }
    }
    //return {sig_figure*figure,sig_power*power-fixed};
    ret=sig_figure*figure;
    fixed=sig_power*power-fixed;
    while(fixed>0){
        ret*=10;
        fixed--;
    }
    while(fixed<0){
        ret/=10;
        fixed++;
    }
    return ret;
}
vector<double> tmp_para_list;
void dfs_calculate(vector<int> &v,int n=0){
    if(n==n_para){
        cout<<"F(";
        for(int i=0;i<n_para;++i){
            cout<<parameters[i]<<"="<<tmp_para_list[i];
            if(i!=n_para-1)cout<<",";
            else cout<<") = ";
        }
        calculate(v,tmp_para_list);
        return;
    }
    for(auto x: para_list_all[n]){
        tmp_para_list.push_back(x);
        dfs_calculate(v,n+1);
        tmp_para_list.pop_back();
    }
}
int main(){
    ios::sync_with_stdio(0);
    string s;
    double _from,_to,_step;
    vector<int> v;
    init();
    cout<<"FBI Warning : power should be positive integer, denominator should be as simple as possible, or simplification may not be correct\n";
    while(cin>>s){
        parameters.clear();
        n_para=0;
        if(format(s,v)){
            cout<<"| Your input: "<<s<<endl<<"| Parameters:\n";
            for(int i=0;i<n_para;++i)cout<<"| "<<i<<" - "<<parameters[i]<<endl;
            //cout<<"| Tansformed code: ";
            //for(auto &x: v)cout<<x<<" ";cout<<endl;
            RPN(v);
            //cout<<"| RPN Code: ";
            //for(auto &x: v)cout<<x<<" ";cout<<endl;
            simplificate(v);
            cout<<"| ";
            for(auto &x: parameters)cout<<x<<" ";cout<<endl;
            for(int i=0;i<n_para;++i){
                para_list_all[i].clear();
                cin>>s;
                if(s[0]>='0'&&s[0]<='9')para_list_all[i].push_back(get_num_double(s));
                else if(s[0]=='{'){
                    s.erase(s.begin());
                    while(_from=get_num_double(s)){
                        para_list_all[i].push_back(_from);
                        if(s[0]=='}')break;
                        else s.erase(s.begin());
                    }
                }else if(s[0]=='['){
                    s.erase(s.begin());
                    _from=get_num_double(s);
                    s.erase(s.begin());
                    _to=get_num_double(s);
                    s.erase(s.begin());
                    _step=get_num_double(s);
                    for(;_from<_to+1e-7;_from+=_step)para_list_all[i].push_back(_from);
                }
            }
            //for(auto x: para_list_all[0])cout<<x<<" ";cout<<endl;
            tmp_para_list.clear();
            dfs_calculate(v);
        }
        else cout<<"error\n";
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/maoruimas/p/10583338.html