简介
简单的表达式计算器,输入一个字符串给出计算结果,数字支持小数,符号支持括号“()”和自定义双目运算符(单字符),预定义了+,-,*,/,%,^六种运算符。原理就是中缀表达式string→后缀表达式vector→利用stack计算。
效果
1.测试代码
// 文件名:main.cpp
#include <iostream>
#include "Calculator.h"
using namespace std;
double difference_of_square(double a, double b) {
// 类型为double(double, double)的函数才能用于注册运算符
return a * a - b * b;
}
int main() {
// 新建一个计算器对象
Calculator cal;
// 像函数一样调用计算表达式,答案1.16
cout << cal("1 + (2 - 3 * 4 / 5) ^ 2") << endl;
// 数字中若有多个小数点则第二个点及之后的数字会被忽略(0.5.123.4 => 0.5),答案-0.5
cout << cal("1 / (4 * 0.5.123.4 - 2*(8^2 % 5 - 2))") << endl;
// 除以0会产生NaN
cout << cal("0 * (1 / 0)") << endl;
// 注册一个平方差运算符’#‘,优先级为3(高于’*‘,’/‘),运算函数为difference_of_square
cal.login('#', 3, difference_of_square);
// 答案0
cout << cal("3 - ((2 + 3) # 4)^0.5") << endl;
// 注销幂运算符'^'
cal.logout('^');
// 此时遇到’^‘运算符将抛出异常
try {
cout << cal("2 ^ 2") << endl;
}
catch (runtime_error re) {
cout << re.what() << endl;
}
}
2.输出
代码
1.头文件
// 文件名:Calculator.h
#pragma once
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <stack>
class Calculator {
public:
Calculator();
void login(char oper, int priory, double(*func)(double, double));
void logout(char oper);
double operator()(const std::string& expr);
private:
std::map<char, int> oper_priorities;
std::map<char, double(*)(double, double)> oper_funcs;
double Calculate(const std::vector<std::string>& postfix);
std::vector<std::string> ToPostfix(const std::string& expr);
static double add(double a, double b);
static double sub(double a, double b);
static double mul(double a, double b);
static double div(double a, double b);
static double mod(double a, double b);
static double pow(double a, double b);
};
2.源文件
// 文件名:Calculator.cpp
#include "Calculator.h"
using namespace std;
Calculator::Calculator() {
oper_priorities['('] = -1;
oper_priorities[')'] = -1;
login('+', 1, add);
login('-', 1, sub);
login('*', 2, mul);
login('/', 2, div);
login('%', 2, mod);
login('^', 3, pow);
}
void Calculator::login(char oper, int priory, double(*func)(double, double)) {
if (oper == '(' || oper == ')') return;
oper_priorities[oper] = priory;
if (func != nullptr) oper_funcs[oper] = func;
}
void Calculator::logout(char oper) {
if (oper == '(' || oper == ')') return;
oper_priorities.erase(oper);
oper_funcs.erase(oper);
}
double Calculator::operator()(const string& expr) {
return Calculate(ToPostfix(expr));
}
double Calculator::Calculate(const vector<string>& postfix) {
stack<double> nums;
for (const string& s : postfix) {
auto it(oper_funcs.find(s[0]));
if (it == oper_funcs.end()) {
nums.push(stod(s));
}
else {
double b = nums.top();
nums.pop();
double a = nums.top();
nums.pop();
nums.push(it->second(a, b));
}
}
return nums.top();
}
vector<string> Calculator::ToPostfix(const string& expr) {
vector<string> postfix;
stack<char> opers;
string num;
for (char c : expr) {
if (c == ' ') continue;
if ('0' <= c && c <= '9' || c == '.') {
num += c;
continue;
}
if (!num.empty()) {
postfix.push_back(num);
num.clear();
}
if (c == '(') {
opers.push(c);
continue;
}
if (c == ')') {
while (!opers.empty() && opers.top() != '(') {
postfix.push_back(string(1, opers.top()));
opers.pop();
}
if (opers.empty()) throw runtime_error("Bracket mismatch");
else opers.pop();
continue;
}
auto it(oper_priorities.find(c));
if (it != oper_priorities.end()) {
while (!opers.empty() && it->second < oper_priorities[opers.top()]) {
postfix.push_back(string(1, opers.top()));
opers.pop();
}
opers.push(c);
continue;
}
throw runtime_error(string("Unknow char: ") + c);
}
if (!num.empty()) postfix.push_back(num);
while (!opers.empty() && opers.top() != '(') {
postfix.push_back(string(1, opers.top()));
opers.pop();
}
if (!opers.empty()) throw runtime_error("Bracket mismatch");
return postfix;
}
double Calculator::add(double a, double b) { return a + b; }
double Calculator::sub(double a, double b) { return a - b; }
double Calculator::mul(double a, double b) { return a * b; }
double Calculator::div(double a, double b) {
if (b == 0) return NAN;
return a / b;
}
double Calculator::mod(double a, double b) {
if (b == 0) return NAN;
return static_cast<int>(a) % static_cast<int>(b);
}
double Calculator::pow(double a, double b) { return std::pow(a, b); }