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;
}