分数计算

#include<bits/stdc++.h>
using namespace std;

int gcd(int a, int b)
{
    a = abs(a);
    b = abs(b);
    int t;
    while(b)
    {
        t=a%b;
        a=b;
        b=t;
    }
    return a;
}

int lcm(int a, int b) 
{
    return a*b/gcd(a, b);
}

class Digit
{
    public:
        int numerator=0;
        int denominator=1;
        Digit(int numerator=0, int denominator=1);
        Digit operator + (Digit b);
        Digit operator - (Digit b);
        Digit operator * (Digit b);
        Digit operator / (Digit b);
};

Digit::Digit(int numerator, int denominator)
{
    this->numerator=numerator;
    this->denominator=denominator;
}

Digit Digit::operator +(Digit b)
{
    Digit t;
    t.denominator=lcm(this->denominator, b.denominator);
    t.numerator=t.denominator/this->denominator*this->numerator+t.denominator/b.denominator*b.numerator;
    int _gcd=gcd(t.numerator, t.denominator);
    t.denominator/=_gcd;
    t.numerator/=_gcd;
    return t;
}

Digit Digit::operator -(Digit b)
{
    Digit t;
    t.denominator=lcm(this->denominator, b.denominator);
    t.numerator=t.denominator/this->denominator*this->numerator-t.denominator/b.denominator*b.numerator;
    int _gcd=gcd(t.numerator, t.denominator);
    t.denominator/=_gcd;
    t.numerator/=_gcd;
    return t;
}

Digit Digit::operator *(Digit b)
{
    Digit t;
    t.denominator=this->denominator*b.denominator;
    t.numerator=this->numerator*b.numerator;
    int _gcd=gcd(t.numerator, t.denominator);
    t.denominator/=_gcd;
    t.numerator/=_gcd;
    return t;
}

Digit Digit::operator /(Digit b)
{
    Digit t;
    swap(b.numerator, b.denominator);
    t.denominator=this->denominator*b.denominator;
    t.numerator=this->numerator*b.numerator;
    int _gcd=gcd(t.numerator, t.denominator);
    t.denominator/=_gcd;
    t.numerator/=_gcd;
    return t;
}

string read_file()
{
    string ans;
    freopen("in.txt","r",stdin);
    getline(cin, ans);
    return ans;
}

bool is_operator(char c)
{
    const int n=4;
    char operators[n+1]="+-*/";
    bool flag=0;
    for(int i=0;i!=n;i++)
    {
        if(c==operators[i])
        {
            flag=1;
            break;
        }
    }
    return flag;
}

bool is_digit(char c)
{
    return c>='0'&&c<='9';
}

bool is_bracket(char c)
{
    return c=='('||c==')';
}

bool check_formula(string str)
{
    int info=0;
    int size=str.size();
    int cnt_bracket=0;
    bool iss[3];
    for(int i=0;i!=size;i++)
    {
        memset(iss, 0, sizeof(iss));
        iss[0]=is_operator(str[i]);
        iss[1]=is_digit(str[i]);
        iss[2]=is_bracket(str[i]);
        if(!iss[0]&&!iss[1]&&!iss[2])
        {
            cout<<str[i]<<endl;
            info=1;
            break;
        }

        if(iss[0])
        {
            if(i==0||str[i-1]=='('||is_operator(str[i-1]))
            {
                info=2;
                break;
            }
        }

        if(iss[2])
        {
            if(str[i]=='(')
            {
                cnt_bracket++;
            }
            if(str[i]==')')
            {
                if(cnt_bracket>0)
                {
                    cnt_bracket--;
                }
                else
                {
                    info=3;
                    break;
                }
            }
        }
    }
    if(cnt_bracket)
    {
        info=4;
    }
    switch(info)
    {
        case 0:break;
        case 1:cout<<"input is wrong! only permite '+-*/()0123456789'"<<endl;break;
        case 2:cout<<"formula is wrong! operator position"<<endl;break;
        case 3:cout<<"too much )"<<endl;break;
        case 4:cout<<"not enough )"<<endl;break;
        default:break;
    }
    return info==0;
}

void push_digit(stack<char> *s_operator, stack<Digit> *s_digit, Digit t) 
{
    if (s_operator->size())
    {
        char c = s_operator->top();
        while (c == '*' || c == '/')
        {
            Digit top = s_digit->top();
            s_digit->pop();
            if (c == '*')
            {
                t = top * t;
            }
            else
            {
                t = top / t;
            }
            s_operator->pop();
            if (s_operator->size())
            {
                c = s_operator->top();
            }
            else
            {
                break;
            }
        }
    }
    s_digit->push(t);
}

string calc(string str)
{
    string ans="";
    stack<char> s_operator;
    stack<Digit> s_digit;
    bool iss[3];
    int size = str.size();
    Digit t;
    for(int i=0;i<size;i++)
    {
        memset(iss, 0, sizeof(iss));
        iss[0]=is_operator(str[i]);
        iss[1]=is_digit(str[i]);
        iss[2]=is_bracket(str[i]);
        //遇到运算符就入栈 
        if(iss[0])
        {
            s_operator.push(str[i]);
        }
        //遇到数字,看看栈顶是不是*/,如果是*/那么就计算,然后
        if(iss[1])
        {
            t.numerator=str[i]-'0';
            i++;
            while(i<size&&is_digit(str[i]))
            {
                t.numerator*=10;
                t.numerator+=(str[i]-'0');
                i++;
            }
            i--;

            push_digit(&s_operator, &s_digit, t);
        }
        //遇到(),(直接入栈,)出栈计算直到遇到( 
        if(iss[2])
        {
            if(str[i]=='(')
            {
                s_operator.push(str[i]);
            }
            else
            {
                char c=s_operator.top();
                s_operator.pop();
                while(c!='(')
                {
                    Digit b=s_digit.top();
                    s_digit.pop();
                    Digit a=s_digit.top();
                    s_digit.pop();
                    if(c=='+')
                    {
                        a=a+b;
                    }
                    if(c=='-')
                    {
                        a=a-b;
                    }
                    if (c == '*')
                    {
                        a = a * b;
                    }
                    if (c == '/')
                    {
                        a = a / b;
                    }
                    push_digit(&s_operator, &s_digit, a);
                    s_operator.pop();
                    c=s_operator.top();
                }
                //防止(前有*/,需要重新触发一下push_digit
                t = s_digit.top();
                s_digit.pop();
                push_digit(&s_operator, &s_digit, t);
            }
        }
    }
    //清空栈
    while(s_operator.size())
    {
        char c=s_operator.top();
        Digit b=s_digit.top();
        s_digit.pop();
        Digit a=s_digit.top();
        s_digit.pop();
        if(c=='+')
        {
            a=a+b;
        }
        if(c=='-')
        {
            a=a-b;
        }
        if (c == '*')
        {
            a = a * b;
        }
        if (c == '/')
        {
            a = a / b;
        }
        push_digit(&s_operator, &s_digit, a);
        s_operator.pop();
    }
    t = s_digit.top();
    s_digit.pop();
    ans=to_string(t.numerator);
    if(t.denominator!=1)
    {
        ans=ans+"/"+to_string(t.denominator);
    }
    return ans;
}

int main() 
{
    string str = read_file();
    if(check_formula(str))
    {
        string ans = calc(str);
        cout<<ans<<endl;
    }
    return 0;
}


文章目录