Update README.md

This commit is contained in:
2025-07-01 23:00:11 +08:00
committed by admin
parent 3b330a9da3
commit 67c9589446
7 changed files with 135 additions and 32 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
## Updata
更新反三角函数的定义域判定,取整函数floor、ceilround和阶乘运算的支持,同时更新变量暂存计算
更新反三角函数的定义域判定,取整函数floor、ceil以及round和阶乘运算的支持,同时更新变量暂存计算
# 数据结构课设
+35 -1
View File
@@ -1,16 +1,35 @@
#include "Calc.h"
#include <iostream>
#include<algorithm>
// 静态成员初始化
Tokenizer Calc::tokenizer;
InfixToPostfix Calc::converter;
PostfixEval Calc::evaluator;
std::unordered_map<std::string, double> Calc::vars = {
{"PAI", 2 * std::asin(1)},
{"pi", 3.14159265358979},
{"e", std::exp(1)}
};
// 主计算接口:表达式字符串 -> 计算结果
double Calc::eval(const string& expression) {
std::string varName, rightExpr;
// 判断是否为赋值表达式,例如 x = 3 + sin(2)
if (is_assign(expression, varName, rightExpr)) {
vector<Token> tokens = tokenizer.run(rightExpr);
vector<Token> postfix = converter.run(tokens);
double val = evaluator.run(postfix, vars);
vars[varName] = val;
return val;
}
vector<Token> tokens = tokenizer.run(expression);
vector<Token> postfix = converter.run(tokens);
return evaluator.run(postfix);
return evaluator.run(postfix,vars);
}
// 安全计算接口:带 try-catch 封装,返回 bool 标志
@@ -42,3 +61,18 @@ void Calc::debug(const string& expr) {
cerr << "[Debug Error] " << e.what() << endl;
}
}
bool Calc::is_assign(const std::string& expr, std::string& varName, std::string& rightExpr) {
size_t eqPos = expr.find('=');
if (eqPos != std::string::npos) {
varName = expr.substr(0, eqPos);
rightExpr = expr.substr(eqPos + 1);
// 去除空格
varName.erase(remove_if(varName.begin(), varName.end(), isspace), varName.end());
rightExpr.erase(remove_if(rightExpr.begin(), rightExpr.end(), isspace), rightExpr.end());
// 检查变量是否合法(只含字母)
return !varName.empty() && std::all_of(varName.begin(), varName.end(), ::isalpha);
}
return false;
}
+5
View File
@@ -23,6 +23,11 @@ private:
static Tokenizer tokenizer;
static InfixToPostfix converter;
static PostfixEval evaluator;
//变量表
static std::unordered_map<std::string, double> vars;
//赋值判断和处理函数
static bool is_assign(const std::string& expr, std::string& varName, std::string& rightExpr);
};
#endif
+13 -8
View File
@@ -14,15 +14,20 @@ vector<Token> InfixToPostfix::run(const vector<Token>& infix) {
//函数压入运算符栈(函数优先级最高)
opStack.push(token);
else if (token.is_ope()) {
//遇到运算符时,弹出栈中优先级更高或相同且结合性为左结合的运算符
while (!opStack.empty() && opStack.top().is_ope() &&
(precedence(opStack.top()) > precedence(token) ||
(precedence(opStack.top()) == precedence(token) && associativity(token) == Associativity::Left))) {
output.push_back(opStack.top());
opStack.pop();
if (token.value == "!")
//后缀操作符直接入栈,不与前面的运算符进行比较
opStack.push(token);
else {
//遇到普通运算符时,弹出栈中优先级更高或相同且结合性为左结合的运算符
while (!opStack.empty() && opStack.top().is_ope() &&
(precedence(opStack.top()) > precedence(token) ||
(precedence(opStack.top()) == precedence(token) && associativity(token) == Associativity::Left))) {
output.push_back(opStack.top());
opStack.pop();
}
//当前运算符入栈
opStack.push(token);
}
//当前运算符入栈
opStack.push(token);
}
else if (token.is_LP())
//遇到左括号,直接入栈
+59 -12
View File
@@ -24,15 +24,25 @@ double PostfixEval::run(const std::vector<Token>& postfix, const unordered_map<s
}
else stk.push(it->second);
}
else if (token.is_ope()) {
//取出两个操作数,执行二元运算
if (stk.size() < 2) throw runtime_error("操作数不足");
double b = stk.top();
stk.pop();
double a = stk.top();
stk.pop();
double res = apply_BO(token.value, a, b);
stk.push(res);
else if (token.is_ope()) {
if (token.value == "!") {
if (stk.empty())
throw runtime_error("阶乘参数不足");
double x = stk.top(); stk.pop();
stk.push(apply_Fac(x));
}
else {
//取出两个操作数,执行二元运算
if (stk.size() < 2)
throw runtime_error("操作数不足");
double b = stk.top();
stk.pop();
double a = stk.top();
stk.pop();
double res = apply_BO(token.value, a, b);
stk.push(res);
}
}
else if (token.is_fun()) {
//取出一个操作数,执行一元基本初等函数的计算
@@ -63,9 +73,16 @@ double PostfixEval::apply_BO(const string& op, double a, double b) {
}
if (op == "^") return pow(a, b);
if (op == "%") {
if (b == 0) throw runtime_error("模除数不能为零");
if (b == 0)
throw runtime_error("模除数不能为零");
return std::fmod(a, b);
}
if (op == "//") {
if (b == 0)
throw runtime_error("整除除数不能为零");
return std::floor(a / b); // 向下取整整除
}
throw runtime_error("未知运算符:" + op);
}
@@ -87,11 +104,41 @@ double PostfixEval::apply_UF(const string& func, double x) {
throw runtime_error("log参数必须大于0");
return log(x);
}
if (f == "ln") {
if(x<=0)
throw runtime_error("ln参数必须大于0");
return log(x) / log(exp(1));
}
if (f == "exp") return exp(x);
if (f == "abs") return fabs(x);
if (f == "asin") return asin(x);
if (f == "acos") return acos(x);
if (f == "asin") {
if (x < -1 || x > 1)
throw runtime_error("asin 参数必须在 [-1, 1] 范围内");
return std::asin(x);
}
if (f == "acos") {
if (x < -1 || x > 1)
throw runtime_error("asin 参数必须在 [-1, 1] 范围内");
return std::acos(x);
}
if (f == "atan") return atan(x);
if (f == "floor") return std::floor(x); // 向下取整
if (f == "ceil") return std::ceil(x); // 向上取整
if (f == "round") return std::round(x); // 四舍五入
throw runtime_error("未知函数:" + func);
}
double PostfixEval::apply_Fac(double x) {
if (x < 0)
throw runtime_error("负数不能求阶乘");
if (x != floor(x))
throw runtime_error("阶乘参数必须为整数");
int n = static_cast<int>(x);
double result = 1;
for (int i = 2; i <= n; ++i)
result *= i;
return result;
}
+3
View File
@@ -20,6 +20,9 @@ private:
//应用于医院基本初等函数,如sin, cos, log
double apply_UF(const string& func, double x);
//应用于一元后缀运算符,如!
double apply_Fac(double x);
};
#endif
+19 -10
View File
@@ -5,27 +5,29 @@
using namespace std;
vector<Token> Tokenizer::run(const string& expr) {
expression = expr;
pos = 0;
vector<Token> tokens;
expression = expr;
pos = 0;
vector<Token> tokens;
// 主循环:逐字符读取表达式
while (pos < expression.length()) {
skipWhitespace();// 跳过空白字符
if (pos >= expression.length()) break;
char current = expression[pos];
// 如果是数字或一元负号开头,读取完整数字
if (is_dig(current) || (current == '-' && is_UMC(tokens)))
if (is_dig(current) || (current == '-' && is_UMC(tokens)))
tokens.push_back(readNumber());
// 如果是字母,读取函数或变量名
else if (is_let(current))
else if (is_let(current))
tokens.push_back(readIdentifier());
// 否则读取操作符或括号
else
else
tokens.push_back(readOperatorOrParen());
}
@@ -69,13 +71,18 @@ Token Tokenizer::readIdentifier() {
//识别函数与变量(若后面紧跟‘(’则为函数,否则为变量)
skipWhitespace();
if (pos < expression.length() && expression[pos] == '(')
if (pos < expression.length() && expression[pos] == '(')
return Token(TokenType::Function, name);
else
else
return Token(TokenType::Variable, name);
}
Token Tokenizer::readOperatorOrParen() {
if (expression[pos] == '/' && pos + 1 < expression.length() && expression[pos + 1] == '/') {
pos += 2; // 跳过两个斜杠
return Token(TokenType::Operator, "//", 2, Associativity::Left);
}
char c = expression[pos++]; // 读取当前字符并自增指针
// 判断字符类型并创建相应 Token
@@ -84,7 +91,9 @@ Token Tokenizer::readOperatorOrParen() {
case '-': return Token(TokenType::Operator, "-", 1, Associativity::Left);
case '*': return Token(TokenType::Operator, "*", 2, Associativity::Left);
case '/': return Token(TokenType::Operator, "/", 2, Associativity::Left);
case '%': return Token(TokenType::Operator, "%", 2, Associativity::Left);
case '^': return Token(TokenType::Operator, "^", 3, Associativity::Right);
case '!': return Token(TokenType::Operator, "!", 4, Associativity::Right);
case '(': return Token(TokenType::LeftParen, "(");
case ')': return Token(TokenType::RightParen, ")");
default:
@@ -111,5 +120,5 @@ bool Tokenizer::is_let(char c) const {
bool Tokenizer::is_OpeCh(char c) const {
// 判断是否为合法的运算符字符
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%';
}