diff --git a/README.md b/README.md index f5c06cd..7ea9793 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## Updata -更新反三角函数的定义域判定,取整函数floor、ceil和round和阶乘运算的支持,同时更新变量暂存计算 +更新反三角函数的定义域判定,取整函数floor、ceil以及round和阶乘运算的支持,同时更新变量暂存计算 # 数据结构课设 diff --git a/ScientificCalculator/Calc.cpp b/ScientificCalculator/Calc.cpp index a50328d..54af5f8 100644 --- a/ScientificCalculator/Calc.cpp +++ b/ScientificCalculator/Calc.cpp @@ -1,16 +1,35 @@ #include "Calc.h" #include +#include // ̬Աʼ Tokenizer Calc::tokenizer; InfixToPostfix Calc::converter; PostfixEval Calc::evaluator; +std::unordered_map 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 tokens = tokenizer.run(rightExpr); + vector postfix = converter.run(tokens); + double val = evaluator.run(postfix, vars); + vars[varName] = val; + return val; + } + vector tokens = tokenizer.run(expression); vector 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; +} + diff --git a/ScientificCalculator/Calc.h b/ScientificCalculator/Calc.h index e312bf0..4406df1 100644 --- a/ScientificCalculator/Calc.h +++ b/ScientificCalculator/Calc.h @@ -23,6 +23,11 @@ private: static Tokenizer tokenizer; static InfixToPostfix converter; static PostfixEval evaluator; + + // + static std::unordered_map vars; + //ֵжϺʹ + static bool is_assign(const std::string& expr, std::string& varName, std::string& rightExpr); }; #endif diff --git a/ScientificCalculator/InfixToPostfix.cpp b/ScientificCalculator/InfixToPostfix.cpp index 1e59c30..9a64fe4 100644 --- a/ScientificCalculator/InfixToPostfix.cpp +++ b/ScientificCalculator/InfixToPostfix.cpp @@ -14,15 +14,20 @@ vector InfixToPostfix::run(const vector& 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()) //ţֱջ diff --git a/ScientificCalculator/PostfixEval.cpp b/ScientificCalculator/PostfixEval.cpp index cb11863..211a94d 100644 --- a/ScientificCalculator/PostfixEval.cpp +++ b/ScientificCalculator/PostfixEval.cpp @@ -24,15 +24,25 @@ double PostfixEval::run(const std::vector& postfix, const unordered_mapsecond); } - 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("log0"); return log(x); } + if (f == "ln") { + if(x<=0) + throw runtime_error("ln0"); + 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(x); + double result = 1; + for (int i = 2; i <= n; ++i) + result *= i; + return result; +} diff --git a/ScientificCalculator/PostfixEval.h b/ScientificCalculator/PostfixEval.h index f1525c3..29ed0bb 100644 --- a/ScientificCalculator/PostfixEval.h +++ b/ScientificCalculator/PostfixEval.h @@ -20,6 +20,9 @@ private: //ӦҽԺȺsin, cos, log double apply_UF(const string& func, double x); + + //ӦһԪ׺,磡 + double apply_Fac(double x); }; #endif diff --git a/ScientificCalculator/Tokenizer.cpp b/ScientificCalculator/Tokenizer.cpp index 17d869f..05e1688 100644 --- a/ScientificCalculator/Tokenizer.cpp +++ b/ScientificCalculator/Tokenizer.cpp @@ -5,27 +5,29 @@ using namespace std; vector Tokenizer::run(const string& expr) { - expression = expr; - pos = 0; - vector tokens; + + expression = expr; + pos = 0; + vector 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 == '%'; +} \ No newline at end of file