Update README.md

This commit is contained in:
2025-07-01 18:33:49 +08:00
committed by KiriAky 107
parent 3b330a9da3
commit 67c9589446
7 changed files with 135 additions and 32 deletions

View File

@@ -1,5 +1,5 @@
## Updata
更新反三角函数的定义域判定取整函数floor、ceilround和阶乘运算的支持同时更新变量暂存计算
更新反三角函数的定义域判定取整函数floor、ceil以及round和阶乘运算的支持同时更新变量暂存计算
# 数据结构课设

View File

@@ -1,16 +1,35 @@
#include "Calc.h"
#include <iostream>
#include<algorithm>
// <20><>̬<EFBFBD><CCAC>Ա<EFBFBD><D4B1>ʼ<EFBFBD><CABC>
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)}
};
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD> -> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double Calc::eval(const string& expression) {
std::string varName, rightExpr;
// <20>ж<EFBFBD><D0B6>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 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);
}
// <20><>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD><EFBFBD>ӿڣ<D3BF><DAA3><EFBFBD> try-catch <20><>װ<EFBFBD><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> bool <20><>־
@@ -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);
// ȥ<><C8A5><EFBFBD>ո<EFBFBD>
varName.erase(remove_if(varName.begin(), varName.end(), isspace), varName.end());
rightExpr.erase(remove_if(rightExpr.begin(), rightExpr.end(), isspace), rightExpr.end());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>Ϸ<EFBFBD><CFB7><EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8>
return !varName.empty() && std::all_of(varName.begin(), varName.end(), ::isalpha);
}
return false;
}

View File

@@ -23,6 +23,11 @@ private:
static Tokenizer tokenizer;
static InfixToPostfix converter;
static PostfixEval evaluator;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static std::unordered_map<std::string, double> vars;
//<2F><>ֵ<EFBFBD>жϺʹ<CFBA><CDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static bool is_assign(const std::string& expr, std::string& varName, std::string& rightExpr);
};
#endif

View File

@@ -14,15 +14,20 @@ vector<Token> InfixToPostfix::run(const vector<Token>& infix) {
//<2F><><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD>ߣ<EFBFBD>
opStack.push(token);
else if (token.is_ope()) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD>߻<EFBFBD><DFBB><EFBFBD>ͬ<EFBFBD>ҽ<EFBFBD><D2BD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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 == "!")
//<2F><>׺<EFBFBD><D7BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>бȽ<D0B1>
opStack.push(token);
else {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD>߻<EFBFBD><DFBB><EFBFBD>ͬ<EFBFBD>ҽ<EFBFBD><D2BD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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();
}
//<2F><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ
opStack.push(token);
}
//<2F><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ
opStack.push(token);
}
else if (token.is_LP())
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ţ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD>ջ

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()) {
//ȡ<><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>ж<EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD>
if (stk.size() < 2) throw runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
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("<EFBFBD>׳˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
double x = stk.top(); stk.pop();
stk.push(apply_Fac(x));
}
else {
//ȡ<><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>ж<EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD>
if (stk.size() < 2)
throw runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
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()) {
//ȡ<><C8A1>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>һԪ<D2BB><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱥ<EFBFBD><C8BA><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
@@ -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("ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>");
if (b == 0)
throw runtime_error("ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>");
return std::fmod(a, b);
}
if (op == "//") {
if (b == 0)
throw runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>");
return std::floor(a / b); // <20><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
throw runtime_error("δ֪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" + op);
}
@@ -87,11 +104,41 @@ double PostfixEval::apply_UF(const string& func, double x) {
throw runtime_error("log<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0");
return log(x);
}
if (f == "ln") {
if(x<=0)
throw runtime_error("ln<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>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 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> [-1, 1] <20><>Χ<EFBFBD><CEA7>");
return std::asin(x);
}
if (f == "acos") {
if (x < -1 || x > 1)
throw runtime_error("asin <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> [-1, 1] <20><>Χ<EFBFBD><CEA7>");
return std::acos(x);
}
if (f == "atan") return atan(x);
if (f == "floor") return std::floor(x); // <20><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>
if (f == "ceil") return std::ceil(x); // <20><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>
if (f == "round") return std::round(x); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
throw runtime_error("δ֪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" + func);
}
double PostfixEval::apply_Fac(double x) {
if (x < 0)
throw runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׳<EFBFBD>");
if (x != floor(x))
throw runtime_error("<EFBFBD>׳˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
int n = static_cast<int>(x);
double result = 1;
for (int i = 2; i <= n; ++i)
result *= i;
return result;
}

View File

@@ -20,6 +20,9 @@ private:
//Ӧ<><D3A6><EFBFBD><EFBFBD>ҽԺ<D2BD><D4BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱥ<EFBFBD><C8BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sin, cos, log
double apply_UF(const string& func, double x);
//Ӧ<><D3A6><EFBFBD><EFBFBD>һԪ<D2BB><D4AA>׺<EFBFBD><D7BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C>
double apply_Fac(double x);
};
#endif

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;
// <20><>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ʽ
while (pos < expression.length()) {
skipWhitespace();// <20><><EFBFBD><EFBFBD><EFBFBD>հ<EFBFBD><D5B0>ַ<EFBFBD>
if (pos >= expression.length()) break;
char current = expression[pos];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD>һԪ<D2BB><D4AA><EFBFBD>ſ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (is_dig(current) || (current == '-' && is_UMC(tokens)))
if (is_dig(current) || (current == '-' && is_UMC(tokens)))
tokens.push_back(readNumber());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
else if (is_let(current))
else if (is_let(current))
tokens.push_back(readIdentifier());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
else
else
tokens.push_back(readOperatorOrParen());
}
@@ -69,13 +71,18 @@ Token Tokenizer::readIdentifier() {
//ʶ<><CAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1>
return Token(TokenType::Operator, "//", 2, Associativity::Left);
}
char c = expression[pos++]; // <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
// <20>ж<EFBFBD><D0B6>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ 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 {
// <20>ж<EFBFBD><D0B6>Ƿ<EFBFBD>Ϊ<EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%';
}