C++计算器

main

#include <iostream>
#include <cmath>       // pow()
#include <stack>
#include <algorithm>
#include <stdexcept>   // runtime_error标准异常库的头文件
#include <string>
#include "baocun.h"
#include "baocun.cpp"
#include "chakanlishi.h"
#include "chakanlishi.cpp"
#include "qingchulishi.h"
#include "qingchulishi.cpp"
#include "jisuangongneng.h"
#include "jisuangongneng.cpp"
#include <cmath>
#define PI 3.141592654
using namespace std;
// 返回运算符的优先级,值越大,优先级越高


void shujuchuli()
{
    stack<double> shuzhi; //存储表达式中的数值
    stack<char> fuhao; //存储表达式中的运算符号
    string shuru;  //输入的表达式文本
    try
    {
        while (true)
        {
            cout << "请输入要计算的表达式,按回车键开始计算" << endl;
            getline(cin, shuru, '\n');//读取从键盘输入的字符串,换行符结束
            string chushi=shuru;
            if (shuru.empty()) break;

            //将表达式的空格删除掉,remove将空格全部移到末尾,返回一个迭代器指向非空格数字范围的end(),也就是指向第一个空格
            shuru.erase(remove(shuru.begin(), shuru.end(), ' '), shuru.end());
            //整理表达式
            while (shuru.find("log")!=-1) {//在系统里显示l
                geshizhengli(shuru,"log","l)");
            }

            while (shuru.find("ln")!=-1) {//在系统里显示n
                int pos=shuru.find("ln");

                if (shuru[pos+2]=='('||(shuru[pos+2]=='-'&&shuru[pos+3]=='(')) {//算sin后得括号//如果有多个括号,找()中有多少个(,再往后找多少个),再从)中间找(,以此类推找到两个)中没有(结束
                    int zkpos{};
                    if (shuru[pos+2]=='(') {
                         zkpos=pos+2;
                    }else if (shuru[pos+2]=='-'&&shuru[pos+3]=='(') {
                         zkpos=pos+3;
                    }
                    int ykpos=shuru.find(")",zkpos);
                    string::iterator it=shuru.begin();
                    if (count(it+zkpos+1,it+ykpos+1,'(')!=0)
                    {
                        int cishu=count(it+zkpos+1,it+ykpos+1,'(');
                        int qianyouk{};
                        while(cishu!=0)
                        {
                            int i{};
                            qianyouk=ykpos;
                            while (i<cishu)
                            {
                                ykpos=shuru.find(")",ykpos+1);
                                i++;
                            }
                            cishu=count(it+qianyouk,it+ykpos+1,'(');
                        }

                    }

                    string sstr=shuru.substr(pos+2,ykpos-pos-1);
                    sstr.insert(0,"(");
                    sstr+="n)";
                    shuru.replace(pos,ykpos-pos+1,sstr);

                }else {
                    size_t zhuanhuan{};
                    string str=to_string(stod(shuru.substr(pos+2), &zhuanhuan));
                    str.insert(0,"(");
                    str+="n)";
                    shuru.replace(pos,2+zhuanhuan,str);
                }

            }

            while (shuru.find("sin")!=-1) {//原理一次性全部转换,有括号的把整个括号一起转,没括号老方式,直到全部没有sin
                    geshizhengli(shuru,"sin","s)");

//                                int pos=shuru.find("sin");

//                if (shuru[pos+3]=='('||(shuru[pos+3]=='-'&&shuru[pos+4]=='(')) {//算sin后得括号//如果有多个括号,找()中有多少个(,再往后找多少个),再从)中间找(,以此类推找到两个)中没有(结束
//                    int zkpos{};
//                    if (shuru[pos+3]=='(') {
//                         zkpos=pos+3;
//                    }else if (shuru[pos+3]=='-'&&shuru[pos+4]=='(') {
//                         zkpos=pos+4;
//                    }
//                    int ykpos=shuru.find(")",zkpos);
//                    string::iterator it=shuru.begin();
//                    if (count(it+zkpos+1,it+ykpos+1,'(')!=0)
//                    {
//                        int cishu=count(it+zkpos+1,it+ykpos+1,'(');
//                        int qianyouk{};
//                        while(cishu!=0)
//                        {
//                            int i{};
//                            qianyouk=ykpos;
//                            while (i<cishu)
//                            {
//                                ykpos=shuru.find(")",ykpos+1);
//                                i++;
//                            }
//                            cishu=count(it+qianyouk,it+ykpos+1,'(');
//                        }

//                    }

//                    string sstr=shuru.substr(pos+3,ykpos-pos-2);
//                    sstr.insert(0,"(");
//                    sstr+="s)";
//                    shuru.replace(pos,ykpos-pos+1,sstr);

//                }else {
//                    size_t zhuanhuan{};
//                    string str=to_string(stod(shuru.substr(pos+3), &zhuanhuan));
//                    str.insert(0,"(");
//                    str+="s)";
//                    shuru.replace(pos,3+zhuanhuan,str);
//                }

                }

            while (shuru.find("cos")!=-1) {//原理一次性全部转换,有括号的把整个括号一起转,没括号老方式,直到全部没有sin
                geshizhengli(shuru,"cos","c)");


            }

            while (shuru.find("tan")!=-1) {//原理一次性全部转换,有括号的把整个括号一起转,没括号老方式,直到全部没有sin
                geshizhengli(shuru,"tan","t)");

            }
            while (shuru.find("PI")!=-1) {
                size_t pos=shuru.find("PI");
                shuru.replace(pos,2,"3.141592654");
            }
            kuohaojiejue(shuru);


            jisuan(shuzhi,fuhao,shuru);
            cout.setf(ios::fixed,ios::floatfield); //不使用科学计算数
            cout.precision(6);//保留两位小数
            cout << "result = " << shuzhi.top() << endl;
            string jieguo=to_string(shuzhi.top());
            baocun(chushi,jieguo);
            while (true) {
                cout <<"继续运算按1,返回上一级按2"<<endl;
                int l;
                cin >>l;
                cin.ignore();
                if (l==2) {
                    system("cls");
                    return;
                }else if (l==1) {
                    break;
                }else {
                    cout <<"请输入正确数字"<<endl;
                }
            }

        }
    }
    catch (const runtime_error& e)//抛出
    {
        cerr << e.what() << endl;//标准错误流,也是输出但是不去缓冲区//当使用e.what()时候无具体的thow信息的能返回系统默认错误,thow返回子类,父类.what()接受
    }
    cout << "计算结束" << endl;
    system("pause");
    system("cls");
    return;
}

int main(){

    while (true) {
        cout <<"欢迎使用计算器,请输入相应的数字"<<endl<<"支持的运算符有+  -  *  /  ^(幂)  &(开方) sin  cos  tan  !(阶乘)  PI(圆周率)  log  ln   %(求余)"<<endl<<"1:打开计算器功能"<<endl<<"2:查看历史记录"<<endl<<"3:清除历史记录"<<endl<<"4:退出计算器"<<endl;
        int a;
        cin >>a;
        cin.ignore();//清空缓冲区,最后打的换行被getline截取了,以为输入了一个空格,所以要清空
        switch (a) {
            case 1:
            shujuchuli();
            break;
             case 2:
            chakanlishi();
            break;
        case 3:
            qingchulishi();
            break;
          case 4:
            system("pause");
           exit(0);
        default:
            cout <<"请输入正确的数字"<<endl;
            system("pause");
            system("cls");
            break;
        }
    }


}

jisuangongneng.h

#include <iostream>
#include <string>
#include <stack>
#include <stdexcept>
#include <cmath>
#define PI 3.141592654
using namespace std;
inline size_t precedence(const char op);
double execute2(char a,stack<double>& shuzhi);
double execute(stack<char>& ops, stack<double>& shuzhi);
void jisuan(stack<double> &shuzhi,stack<char> &fuhao,string shuru);
void kuohaojiejue(string &shuru);
void geshizhengli(string &shuru,string houzhui);

jisuangongneng.cpp

#include "chakanlishi.h"
#define PI 3.141592654
#include <stack>
#include <cmath>
void jisuan(stack<double> &shuzhi,stack<char> &fuhao,string shuru);
//格式解决
void geshizhengli(string &shuru,string fuhao,string houzhui){
    int pos=shuru.find(fuhao);

    if (shuru[pos+3]=='('||(shuru[pos+3]=='-'&&shuru[pos+4]=='(')) {//算sin后得括号//如果有多个括号,找()中有多少个(,再往后找多少个),再从)中间找(,以此类推找到两个)中没有(结束
        int zkpos{};
        if (shuru[pos+3]=='(') {
             zkpos=pos+3;
        }else if (shuru[pos+3]=='-'&&shuru[pos+4]=='(') {
             zkpos=pos+4;
        }
        int ykpos=shuru.find(")",zkpos);
        string::iterator it=shuru.begin();
        if (count(it+zkpos+1,it+ykpos+1,'(')!=0)
        {
            int cishu=count(it+zkpos+1,it+ykpos+1,'(');
            int qianyouk{};
            while(cishu!=0)
            {
                int i{};
                qianyouk=ykpos;
                while (i<cishu)
                {
                    ykpos=shuru.find(")",ykpos+1);
                    i++;
                }
                cishu=count(it+qianyouk,it+ykpos+1,'(');
            }

        }

        string sstr=shuru.substr(pos+3,ykpos-pos-2);
        sstr.insert(0,"(");
        sstr+=houzhui;
        shuru.replace(pos,ykpos-pos+1,sstr);

    }else {
        size_t zhuanhuan{};
        string str=to_string(stod(shuru.substr(pos+3), &zhuanhuan));
        str.insert(0,"(");
        str+=houzhui;
        shuru.replace(pos,3+zhuanhuan,str);
    }
    cout <<shuru<<endl;
}
//括号解决
void kuohaojiejue(string &shuru){
    //括号,把最右的算出来

     while(shuru.find("(")!=-1) {

         int pos=shuru.find("(");
         ++pos;
         while (shuru.find("(",pos)!=-1){
             pos=shuru.find("(",pos);
             ++pos;
         }
         if (count(shuru.begin(),shuru.end(),'(')!=count(shuru.begin(),shuru.end(),')')) {
             throw runtime_error("括号数量不对称");
         }else if (pos==shuru.length()) {
             throw runtime_error("左括号不能在末尾");
         }else if (shuru[pos]==')') {
             throw runtime_error("括号内无内容");
         }else if (shuru[pos]=='*'||shuru[pos]=='/') {
             throw runtime_error("格式错误");
         }else if ((pos-1)!=0) {
             if (shuru[pos-2]=='1'||shuru[pos-2]=='2'||shuru[pos-2]=='3'||shuru[pos-2]=='4'||shuru[pos-2]=='5'||shuru[pos-2]=='6'||shuru[pos-2]=='7'||shuru[pos-2]=='8'||shuru[pos-2]=='9'||shuru[pos-2]=='0'||shuru[pos-2]=='.'||shuru[pos-2]==')') {
             throw runtime_error("左括号前面不能为数字和小数点");
             }

         }

         string skuohao=shuru.substr(pos,(shuru.find(")",pos)-pos));
         int posw=shuru.find(")",pos);
         if (shuru[posw+1]=='1'||shuru[posw+1]=='2'||shuru[posw+1]=='3'||shuru[posw+1]=='4'||shuru[posw+1]=='5'||shuru[posw+1]=='6'||shuru[posw+1]=='7'||shuru[posw+1]=='8'||shuru[posw+1]=='9'||shuru[posw+1]=='0'||shuru[posw+1]=='.'||shuru[posw+1]=='(') {
                             throw runtime_error("右括号后面不能为数字、小数点和左括号");
                         }
         stack<double> sshuzhi;
         stack<char> sfuhao;
         jisuan(sshuzhi,sfuhao,skuohao);
          pos--;
         shuru.replace(pos,posw-pos+1,to_string(sshuzhi.top()));
cout <<shuru<<endl;
     }

}


inline size_t precedence(const char op)
{
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/'|| op == '%')
        return 2;
    if (op == '^' || op == '&')//&开方 8&3 相当于8开3次方
        return 3;
    if (op == 's' || op == 'c'|| op == 't'|| op == '!'|| op == 'l'|| op == 'n')
        return 4;
    throw runtime_error{ string {"表达中包含无效的运算符"} +op };

}
//计算三教
double execute2(char a,stack<double>& shuzhi)
{
    double result{};
    double czs=shuzhi.top(); // 得到右操作数
    shuzhi.pop();

    switch (a) // 根据两个操作数之间的运算符,执行相应计算
    {
    case 's':
        result = sin(czs * PI / 180.f);
        break;
    case 'c':
        result = cos(czs* PI / 180.f);
        break;
    case 't':
        result = tan(czs* PI / 180.f);
        break;
   case 'l':
        if (czs<=0) {
            throw runtime_error("负数不能作为log的参数");
        }
        result = log10(czs);
        break;
    case 'n':
        if (czs<=0) {
            throw runtime_error("负数不能作为ln的参数");
        }
        result = log(czs);
        break;
    case '!':
        if (czs<0) {
            throw runtime_error("负数不能阶乘");
        }else if(czs==0||czs==1){
            result=1;
            break;
        }else if(czs<1&&czs>0){
            throw runtime_error("请输入正整数进行阶乘操作");
        }else if(czs>1){
            if ((czs-((int)czs))==0) {
                double num=1;
                for (int i=1;i<=czs;i++) {
                    num*=i;
                }
                result = num;
                break;
            }else {
            throw runtime_error("请输入正整数进行阶乘操作");
}

}

    default:
        throw runtime_error(string("invalid operator: ") +a);
    }
    shuzhi.push(result);//将新计算出来的结果入栈
    return result;
}
// 计算加减
double execute(stack<char>& ops, stack<double>& shuzhi)
{
    double result{};
    double yczs=shuzhi.top(); // 得到右操作数
    shuzhi.pop();
    double zczs=shuzhi.top(); // 得到做操作数
    shuzhi.pop();

    switch (ops.top()) // 根据两个操作数之间的运算符,执行相应计算
    {
    case '+':
        result = zczs + yczs;
        break;
    case '-':
        result = zczs - yczs;
        break;
    case '*':
        result = zczs * yczs;
        break;
    case '%':
        if (zczs!=(int)zczs||yczs!=(int)yczs) {
            throw runtime_error("小数不能求余");
        }
        result = (int)zczs % (int)yczs;
        break;
    case '/':
        if (yczs==0) {
            throw runtime_error("除数不能为0");
        }
        result = zczs / yczs;
        break;
    case '^':
        result = pow(zczs, yczs);
        break;
    case '&':
        if (zczs<=0) {
            throw runtime_error{string("非法操作")};
        }
        result = pow(zczs, (double)1.0/yczs);
        break;

    default:
        throw runtime_error(string("invalid operator: ") +ops.top());
    }
    ops.pop(); //计算完成后,该运算符要弹栈
    shuzhi.push(result);//将新计算出来的结果入栈
    return result;
}

void jisuan(stack<double> &shuzhi,stack<char> &fuhao,string shuru){
    //先去除掉重复的-;负负得正
     //防止出现两个--,截取不出数字现象

    while (shuru.find("--")!=-1) {
        int pos=shuru.find("--");
        if (pos==0) {
                         shuru.erase(pos,2);
                     }else if (pos>=1) {
                         if (shuru[pos-1]=='+'||shuru[pos-1]=='*'||shuru[pos-1]=='/') {
                             shuru.erase(pos,2);
                         }
                         else if (shuru[pos+2]=='-') {
                             shuru.erase(pos,2);
                         }else {
                             shuru.replace(pos,2,"+");

                     }
                    }
    }

    size_t index{};
    //index表示该数字的位数//stod可以截取小数和负数,.11会截取出0.11,截到数字结束,截取完成后index指向数字的下一个位置,stod只能截取字符串头位置
    shuzhi.push(stod(shuru, &index)); // 将表达式中第一个数字进栈//截取字符串中的第一个数字转换为double类型
    if (index!=shuru.length()) {
        while (true)
        {   if (shuru[index]=='s'||shuru[index]=='c'||shuru[index]=='t'||shuru[index]=='!'||shuru[index]=='l'||shuru[index]=='n') {
                execute2(shuru[index],shuzhi);
                index++;
                if (index == shuru.length())
                {
                    while (!fuhao.empty())  //如果 fuhao不为空,表示还没有计算完
                        execute(fuhao, shuzhi);
                    break;
                }
    }
            fuhao.push (shuru[index++]); // 将运算符进栈

            size_t i{};
            shuzhi.push(stod(shuru.substr(index), &i));  //将运算符后的数字也进栈,并将数字的位数赋值给 i。//substr截取从index开始的字符串,默认截取全部
            index += i;  //更新 index

            if (index == shuru.length())
            {
                while (!fuhao.empty())  //如果 fuhao不为空,表示还没有计算完
                    execute(fuhao, shuzhi);
                break;
            }
            //如果表达式还未遍历完,但子表达式中的运算符优先级比其后面的运算符优先级大,就先计算当前的子表达式(已经插入的)的值
            while (!fuhao.empty() && precedence(shuru[index]) <= precedence(fuhao.top()))
                execute(fuhao, shuzhi);
        }
    }

}

baocun.h

#include <iostream>
#include <string>
using namespace std;
void baocun(const string &str,const double &jieguo);

baocun.cpp

#include "baocun.h"
#include <fstream>
void baocun(string str,string jieguo){
    ofstream ofs("lishijilu.txt",ios::out|ios::app);
    ofs <<str<<' '<<jieguo<<endl;
    ofs.close();
    return;
}

chakanlishi.h

#include <iostream>
#include <string>
using namespace std;
void chakanlishi();

chakanlishi.cpp

#include "chakanlishi.h"
#include <fstream>
using namespace std;
void chakanlishi(){
    ifstream ifs("lishijilu.txt",ios::in);
    if (!ifs.is_open()) {
        cout <<"没有找到历史文件"<<endl;
        system("pause");
        system("cls");
        return;
    }
    char ceshi;
    ifs >>ceshi;
    if (ifs.eof()) {
        cout <<"无历史记录"<<endl;
        system("pause");
        system("cls");
        return;
    }
    ifs.putback(ceshi);
    string bds;
    string jieguo;
    cout <<"历史计算记录有:"<<endl;
    while (ifs>>bds>>jieguo) {

        cout <<"表达式:"<<bds<<"  计算结果为:"<<jieguo<<endl;
    }
    ifs.close();
    system("pause");
    system("cls");
    return;

}

qingchulishi.h

#include <iostream>
#include <string>
using namespace std;
void qingchulishi();

qingchulishi.cpp

#include "qingchulishi.h"
#include <fstream>
void qingchulishi(){
    ofstream ofs("lishijilu.txt",ios::trunc);
    ofs.close();
    cout <<"已经成功清除"<<endl;
    system("pause");
    system("cls");
    return;


}

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值