C++ 四则运算eval初实现,对输入函数用矩形法实现积分【新手联习】附代码

        刚刚开始学c++,老师让我实现对函数的微积分。对于我来说,不算轻松,经过一番搜索和训练。我的思路是这样子的:

1.首先要识别函数,就要实现像python里的eval函数,通过中缀表达式转后缀表达式

2.识别类似于三角函数的数学公式

3.对函数中的变量进行赋值,去微积分。

在第一步,就是常规的得到后缀表达式,详细逻辑可以参考下面链接思路讲的挺清晰,我就是从这里学习的,我对他的代码进行了一个修改,满足更多功能。c++后缀表达式实现eval详解(附代码)_浪子小院的博客-CSDN博客

中缀转后缀
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <string>
#include<string.h>
#include <vector>
#include <map>
#include<math.h>
using namespace std;

//方便后续查找是否为运算符
string ops = "+-*/()^";

//将字符串转为double型
double todouble(string str)
{
	double target;
	stringstream strs;
	strs << str;
	strs >> target;
	return target;
}

//初始化运算符优先级表,一定得初始化
void newmap(map<string, int>& m)
{
	
	m.insert(make_pair("+" ,0));
	m.insert(make_pair("-", 0));
	m.insert(make_pair("*", 1));
	m.insert(make_pair("/", 1));
	m.insert(make_pair("^", 2));
	m.insert(make_pair("(", 3));
	m.insert(make_pair(")", 3));	
}
//将中缀表达式转为后缀表达式
vector<string> topostfix(string str)
{
	vector<string> result;//存放后缀表达式
	vector<string> ops_stack;//存放操作符
	string numtemp, opstemp;
	for (int i = 0; i < str.size(); i++)
	{
		
		if (i == 0 && str[i] == '-')//如果第一个字符是“-”,则判定为一个负数
		{
			numtemp += str[i];
			continue;
		}
		if (ops.find(str[i]) == -1)//判断为数字
		{
			numtemp += str[i];
		}
		else//判断为操作符
		{
			if (i > 0)//负数的判定
			{
				if (str[i] == '-' && str[i - 1] == '(')
				{
					numtemp += str[i];
					continue;
				}
				if (str[i] == '-' && str[i - 1] == '*')
				{
					numtemp += str[i];
					continue;
				}
				if (str[i] == '-' && str[i - 1] == '/')
				{
					numtemp += str[i];
					continue;
				}
				if (str[i] == '-' && str[i - 1] == '^')
				{
					numtemp += str[i];
					continue;
				}
			}
			if (!numtemp.empty())//如果numtemp不为空,将其入栈
			{
				result.push_back(numtemp);
				numtemp.clear();
			}
			opstemp = str[i];
			//如果ops_stack为空,opstemp直接入栈
			if (ops_stack.empty())
			{
				ops_stack.push_back(opstemp);
			}
			//opstemp为"("直接入栈
			else if (opstemp == "(")
			{
				ops_stack.push_back(opstemp);
			}
			//opstemp为")",需要ops_stack直到"("前都弹出栈,包括"("
			else if (opstemp == ")")
			{
				while (ops_stack.back() != "(")
				{
					result.push_back(ops_stack.back());
					ops_stack.pop_back();
					if (ops_stack.empty())
					{
						cout << "表达式出现错误" << endl;
						result.push_back("0");
						return result;
					}
				}
				ops_stack.pop_back();
			}
			//栈顶为"(",且当前操作符不为括号,入栈
			else if (ops_stack.back() == "(")
			{
				ops_stack.push_back(opstemp);
			}
			//当前操作符的优先级高于栈顶操作符优先级,入栈
			else if (m[opstemp] > m[ops_stack.back()])
			{
				ops_stack.push_back(opstemp);
			}
			//当前操作符的优先级小于或等于栈顶操作符优先级,弹出栈顶元素,直到大于栈顶操作符优先级,或为空
			else
			{
				while ((ops_stack.back() != "(") && (m[opstemp] <= m[ops_stack.back()]))
				{
					result.push_back(ops_stack.back());
					ops_stack.pop_back();
					if (ops_stack.empty())//栈空
					{
						break;
					}
				}
				ops_stack.push_back(opstemp);
			}
			
		}
	}
	if(!numtemp.empty())
	result.push_back(numtemp);//如果最后有数字,将最后的数字补上
	//要是操作符栈还有元素,全部弹出到result
	while (!ops_stack.empty())
	{
		result.push_back(ops_stack.back());
		ops_stack.pop_back();
	}
	return result;
}
 计算后缀表达式
//计算后缀运算符
double calpostfix(const vector<string>& postfix)
{
	vector<double> numelements;
	for (int i = 0; i < postfix.size(); i++)
	{
		if (ops.find(postfix[i]) == -1)//判断为数字
		{
			numelements.push_back(todouble(postfix[i]));
		}
		else//判断为操作符
		{
			double num1 = numelements.back();
			numelements.pop_back();
			double num2 = numelements.back();
			numelements.pop_back();
			double ret = 0;
			if (postfix[i] == "+")//"+"运算
			{
				ret = num1 + num2;		
			}
			if (postfix[i] == "-")//"-"运算
			{
				ret = num1 - num2;
			}
			if (postfix[i] == "*")//"*"运算
			{
				ret = num1 * num2;
			}
			if (postfix[i] == "/")//"/"运算
			{
				if (num2 == 0)
				{
					cout << "错误" << endl;
					return 0;
				}
				ret = num1 / num2;
			}
			if (postfix[i] == "^")//"^"运算
			{
				ret = pow(num1, num2);
			}
			numelements.push_back(ret);
		}
	}
	if (numelements.size() == 1)
	{
		return numelements.back();
	}
	else
	{
		cout << "错误" << endl;
		return 0;
	}
}
识别数学公式,类似三角函数

这里我感觉我的思路有点笨,先对字符串进行判断,是否含有三角函数,提前算好,将数值替代进字符串,我感觉有比我这个好很多的思路和做法,请各位大哥指点一哈,更好的方法。

//方便后续查找数学函数
string hanshu = "sincostan";

//将double型转为string型
string tostring(double d)
{
	string s;
	stringstream strs;
	 strs<<d;
	strs >> s;
	return s;
}

//将字符串中的一部分替换为另一部分
string string_replace(string str1, string str2, string str3)
{
	while (str1.find(str2) != -1)
	{
		int index = str1.find(str2);
		str1.replace(index, str2.size(), str3);
	}
	return str1;
}

//将字符串中存在的三角函数先算完
string tonewstr(string str)
{
	const char* c;
	const char* s;
	const char* t;
	c = strstr(str.c_str(), "cos");
	s = strstr(str.c_str(), "sin");
	t = strstr(str.c_str(), "tan");
	while (c != NULL || s != NULL || t != NULL)//判断字符串中是否含有三角函数
	{
		if (c != NULL)//计算完cos且将str中的cos()替换为其值
		{
			int num = 0;//这儿感觉可以封装成一个函数,简洁一点
			int lk = 1;
			int rk = 0;
			int index = str.find("cos") + 4;
			for (int i = index; lk != rk; i++)
			{
				if (str[i] == '(')
				{
					lk++;
				}
				if (str[i] == ')')
				{
					rk++;
				}
				num++;
			}
			string newstr;
			newstr = str.substr(index, num-1);
			double r;
			if (str.size() == 1)//如果只有一个数则直接计算
			{
				r = cos(todouble(newstr));
			}
			else
			{
				r = cos(eval(newstr));
			}
			str = str.replace(str.find("cos"), num + 4, tostring(r));
			c= strstr(str.c_str(), "cos");
		}
		if (s != NULL)//计算完sin且将str中的sin()替换为其值
		{
			int num = 0;
			int lk = 1;
			int rk = 0;
			int index = str.find("sin") + 4;
			for (int i = index; lk != rk; i++)
			{
				if (str[i] == '(')
				{
					lk++;
				}
				if (str[i] == ')')
				{
					rk++;
				}
				num++;
			}
			string newstr;
			newstr = str.substr(index, num - 1);
			double r;
			if (str.size() == 1)//如果只有一个数则直接计算
			{
				r = cos(todouble(newstr));
			}
			else
			{
				r = cos(eval(newstr));
			}
			str = str.replace(str.find("sin"), num + 4, tostring(r));
			s = strstr(str.c_str(), "sin");
		}
		if (t != NULL)//计算完tan且将str中的tan()替换为其值
		{
			int num = 0;
			int lk = 1;
			int rk = 0;
			int index = str.find("tan") + 4;
			for (int i = index; lk != rk; i++)
			{
				if (str[i] == '(')
				{
					lk++;
				}
				if (str[i] == ')')
				{
					rk++;
				}
				num++;
			}
			string newstr;
			newstr = str.substr(index, num - 1);
			double r;
			if (str.size() == 1)//如果只有一个数则直接计算
			{
				r = cos(todouble(newstr));
			}
			else
			{
				r = cos(eval(newstr));
			}
			str = str.replace(str.find("tan"), num + 4, tostring(r));
			t = strstr(str.c_str(), "tan");
		}
	}
	str=string_replace(str, "+-", "-");//把1+-2类型的转为1-2
	str=string_replace(str, "--", "+");//负负得正
	return str;
}
整合一哈eval函数
//解析字符串且计算
double eval(string str)
{
	vector<string> result;
	result=topostfix(tonewstr(str));
	return calpostfix(result);
}
实现微积分(我数学不好,有错请指出)
void test2()//实现微积分
{
	string str;
	newmap(m);//初始化map数组
	int choice;
	while(str!="exit")
	{
		double x;
		string strx;
		cout << "请输入函数表达式(用x表达): " << endl;
		cin >> str;
		cout << "请选择进行微分(1)或者积分(2):" << endl;
		cin >> choice;
		if (choice == 1)
		{
			double xo;
			string str1;
			string str2;
			string strxo;
			cout << "请输入进行微分的点位,Xo = " << endl;
			cin >> xo;
			x = xo + 0.001;
			strx = tostring(x);
			strxo = tostring(xo);
			str1 = string_replace(str, "x", strx);
			str2 = string_replace(str, "x", strxo);
			cout << "在Xo处的微分是:" << eval(str1) - eval(str2) << endl;
		}
		else if (choice == 2)
		{
			double a;
			double b;
			double sum=0;
			string newstr;
			cout << "请输入积分的下标:" << endl;
			cin >> b;
			cout << "请输入积分的上标" << endl;
			cin >> a;
			x = b;
			while (x <= a)//也可以自己设定一个分割次数,我定的1000
			{
				strx = tostring(x);
				newstr = string_replace(str, "x", strx);
				cout << newstr << endl;
				sum += eval(newstr);
				x += 0.001;
			}
			cout << "其定积分为:" << (sum/1000) << endl;
		}
		else
		{
			cout << "输入错误,请重新输入" << endl;
			continue;
		}
	}
}
int main()
{
	
	test2();
	return 0;
}
总结

 我编完的总体感觉,就是整个代码好臃肿,而且很局限,对微积分的实现精确度不高,而且只有一元和简单的公式。我看到一个矩阵法求微积分,感觉会更加精确简洁,等我学懂,再出一期。

(ps:第一篇文,很多不足的地方多多包涵,有错请指出)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值