实现一个可灵活扩充功能的计算器, 面向对象设计
可以灵活添加绝大部分运算操作符
并附带ui 界面方便使用
g++ -fPIC -shared main.cpp -std=c++17 -o cal.so
比如支持 & bit_and 运算 比如 10 & 5
只需要修改如下
class BitAndOperator : public Operator {
public:
BitAndOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0] & buffer[1];
}
};
int priority(char op) {
switch (op) {
case '(':
return 100000;
case '!':
case '~':
case 'z': // z --> 一元+
case 'y': // y --> 一元-
case 's':
return 10000;
case '*':
case '/':
case '%':
return 1000;
case '+':
case '-':
return 100;
case '&':
case '^':
return 50;
case ')':
return -1;
default:
return 0;
}
}
unordered_map<char, Operator*> RPN::opfunc_map {
{'z', new UnaryAddOperator},
{'y', new UnarySubOperator},
{'+', new AddOperator},
{'-', new SubOperator},
{'*', new MultiplyOpeator},
{'/', new DivideOperator},
{'s', new SinOperator},
{'&', new BitAndOperator},
};
#include
#include
#include
#include
#include
#include
using namespace std;
/**** 基本计算器
* 支持运算符
* 一元运算符 特殊处理 - -> _ +直接删去
* 二元运算符 + - * /
* 特殊() [] {}
* 扩充一元运算符
* sin -> s
* cos -> c
* tan -> t
*
* 扩充二元运算符 |(二进制与) &(二进制或) ^(二进制异或)
*/
using OPTYPE = double;
int err_no = 0;
class Operator {
private:
int cnt = 2;
virtual OPTYPE cal(OPTYPE *buffer) = 0;
public:
explicit Operator(int cnt) : cnt(cnt) {}
virtual OPTYPE cal(stack<OPTYPE> &st) {
if (st.size() < cnt) {
cout << "st.size() < cnt";
err_no = -1;
return errno;
}
OPTYPE buffer[cnt];
int idx = cnt;
while (idx-- > 0) {
buffer[idx] = st.top();
st.pop();
}
return cal(buffer);
}
};
class UnaryAddOperator : public Operator {
public:
explicit UnaryAddOperator() : Operator(1) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0];
}
};
class UnarySubOperator : public Operator {
public:
UnarySubOperator() : Operator(1) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return -buffer[0];
}
};
class AddOperator : public Operator {
public:
explicit AddOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0] + buffer[1];
}
};
class SubOperator : public Operator {
public:
explicit SubOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0] - buffer[1];
}
};
class MultiplyOpeator : public Operator {
public:
MultiplyOpeator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0] * buffer[1];
}
};
class DivideOperator : public Operator {
public:
DivideOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return buffer[0] / buffer[1];
}
};
class SinOperator : public Operator {
public:
SinOperator() : Operator(1) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return sin(buffer[0]);
}
};
class CosOperator : public Operator {
public:
CosOperator() : Operator(1) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return cos(buffer[0]);
}
};
class TanOperator : public Operator {
public:
TanOperator() : Operator(1) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return tan(buffer[0]);
}
};
class ModOperator : public Operator {
public:
ModOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
return (long long) buffer[0] % (long long) buffer[1];
}
};
class BitAndOperator : public Operator {
public:
BitAndOperator() : Operator(2) {}
private:
OPTYPE cal(OPTYPE *buffer) override {
if constexpr(sizeof(OPTYPE) == 8) {
return (long long) buffer[0] & (long long) buffer[1];
}
return (int) buffer[0] & (int) buffer[1];
}
};
class RPN {
private:
static unordered_map<string, char> opname_map;
static unordered_set<char> canMiss;
string rpn;
string result;
static unordered_map<char, Operator *> opfunc_map;
// 左结合运算符 取正
// 右结合运算符取负, 目前只支持sin cos tan
int priority(char op) {
switch (op) {
case '(':
return 100000;
case '!':
case '~':
case 'z': // z --> 一元+
case 'y': // y --> 一元-
return 10000;
case '*':
case '/':
case '%':
return 1000;
case '+':
case '-':
return 100;
case '&':
case '^':
return 50;
case ')':
return 0;
case 's':
case 't':
case 'c':
return -10000;
default:
return 0;
}
}
// 特殊处理
string formatSpecialFix(const string s) {
string ans;
bool has_num = false;
for (int i = 0; i < s.size(); i++) {
switch (s[i]) {
case '+':
case '-': {
bool unary = false;
if (i == 0) {
unary = true;
} else {
int j = i;
while (j - 1 >= 0 && canMiss.count(s[j - 1])) {
j--;
}
if (j - 1 >= 0 && s[j - 1] == '(') {
unary = true;
}
}
if (unary) {
string temp(1, s[i]);
ans.push_back(opname_map[temp]);
} else {
ans.push_back(s[i]);
}
break;
}
case 's':
case 'c':
case 't': {
if (i + 3 >= s.size()) {
err_no = -4;
cout << "bad op";
return "bad";
}
string temp = s.substr(i, 3);
if (opname_map.count(temp) == 0) {
err_no = -2;
cout << "op not exit";
return "bad";
}
ans.push_back(opname_map[temp]);
i += 2;
break;
}
default:
ans.push_back(s[i]);
}
}
return ans;
}
void pop_until(char ch, stack<char> &st) {
if (ch != '(' && priority(ch) < 0) {
st.push(ch);
return;
}
while (!st.empty() && st.top() != '(' && priority(st.top()) >= priority(ch)) {
rpn.push_back(st.top());
st.pop();
}
if (ch == ')') {
st.pop();
} else {
st.push(ch);
};
}
public:
string getResult() {
return result;
}
void pn_to_rpn(const string &s) {
string fixStr = formatSpecialFix(s);
if (err_no != 0) {
return;
}
cout << fixStr << endl;
stack<char> st;
for (int i = 0; i < fixStr.size(); i++) {
if (canMiss.count(fixStr[i])) {
continue;
}
if (isdigit(fixStr[i])) {
rpn.push_back(fixStr[i]);
while (i + 1 < fixStr.size() && (isdigit(fixStr[i + 1]) || fixStr[i + 1] == '.')) {
rpn.push_back(fixStr[i + 1]);
i++;
}
} else if (fixStr[i] == '(') {
st.push(fixStr[i]);
continue;
} else {
pop_until(fixStr[i], st);
}
rpn.push_back(' ');
}
while (!st.empty()) {
rpn.push_back(st.top());
st.pop();
}
}
OPTYPE cal() {
cout << rpn << endl;
stack<OPTYPE> st;
for (int i = 0; i < rpn.size(); i++) {
// 空字符
if (canMiss.count(rpn[i])) {
continue;
}
// 数字
if (isdigit(rpn[i])) {
bool dot = false;
double base = 0.1;
OPTYPE value = rpn[i] - '0';
while (i + 1 < rpn.size() && (isdigit(rpn[i + 1]) || rpn[i + 1] == '.')) {
if (rpn[i + 1] == '.') {
dot = true;
} else {
if (!dot) {
value = value * 10 + (rpn[i + 1] - '0');
} else {
value += ((rpn[i + 1] - '0') * base);
base /= 10;
}
}
i++;
}
st.push(value);
continue;
}
if (opfunc_map.count(rpn[i]) == 0) {
err_no = -3;
cout << "unsupport op";
break;
}
auto op = opfunc_map[rpn[i]];
auto v = op->cal(st);
if (err_no != 0) {
break;
}
cout << v << endl;
st.push(v);
}
if (err_no != 0) {
return INT64_MIN;
}
cout << st.top() << endl;
return st.top();
}
};
unordered_map<string, char> RPN::opname_map{
{"+", 'z'},
{"-", 'y'},
{"tan", 't'},
{"sin", 's'},
{"cos", 'c'},
};
unordered_set<char> RPN::canMiss{' '};
unordered_map<char, Operator *> RPN::opfunc_map{
{'z', new UnaryAddOperator},
{'y', new UnarySubOperator},
{'+', new AddOperator},
{'-', new SubOperator},
{'*', new MultiplyOpeator},
{'/', new DivideOperator},
{'s', new SinOperator},
{'c', new CosOperator},
{'t', new TanOperator},
{'%', new ModOperator},
{'&', new BitAndOperator},
};
extern "C" {
OPTYPE calculate(const char *s) {
err_no = 0;
RPN rpn;
rpn.pn_to_rpn(s);
if (err_no != 0) {
return INT64_MIN;
}
return rpn.cal();
}
}
//
int main() {
cout << calculate("sincostan6");
}
"""
实现带界面的计算器(可做加减乘除操作)
"""
from tkinter import *
import tkinter.font
from functools import partial
import ctypes
import platform
calculator = ctypes.CDLL('./cal.so')
calculator.calculate.restype = ctypes.c_double
def get_input(entry, argu):
entry.insert(END, argu)
def backspace(entry):
input_len = len(entry.get())
entry.delete(input_len - 1)
def clear(entry):
entry.delete(0, END)
def calc(entry):
input = entry.get().strip()
#output2 = str(eval(input))
# print(output2)
bs = ctypes.c_char_p(bytes(input, encoding="utf8"))
output = calculator.calculate(bs)
if output == -9223372036854775808:
output = 'error'
clear(entry)
# if output2 != output:
# entry.insert(END, output)
# entry.insert(END, "\t")
# entry.insert(END, output2)
# else:
entry.insert(END, output)
def cal():
root = Tk()
root.title("我的计算器")
root.resizable(0, 0)
entry_font = tkinter.font.Font(size=12)
entry = Entry(root, justify="right", font=entry_font)
entry.grid(row=0, column=0, columnspan=4, sticky=N + W + S + E, padx=5, pady=5)
button_font = tkinter.font.Font(size=10, weight=tkinter.font.BOLD)
button_bg = '#D5E0EE'
button_active_bg = '#E5E35B'
myButton = partial(Button, root, bg=button_bg, padx=10, pady=3, activebackground=button_active_bg)
button7 = myButton(text='7', command=lambda: get_input(entry, '7'))
button7.grid(row=1, column=0, pady=5)
button8 = myButton(text='8', command=lambda: get_input(entry, '8'))
button8.grid(row=1, column=1, pady=5)
button9 = myButton(text='9', command=lambda: get_input(entry, '9'))
button9.grid(row=1, column=2, pady=5)
button10 = myButton(text='+', command=lambda: get_input(entry, '+'))
button10.grid(row=1, column=3, pady=5)
button4 = myButton(text='4', command=lambda: get_input(entry, '4'))
button4.grid(row=2, column=0, pady=5)
button5 = myButton(text='5', command=lambda: get_input(entry, '5'))
button5.grid(row=2, column=1, pady=5)
button6 = myButton(text='6', command=lambda: get_input(entry, '6'))
button6.grid(row=2, column=2, pady=5)
button11 = myButton(text='-', command=lambda: get_input(entry, '-'))
button11.grid(row=2, column=3, pady=5)
button1 = myButton(text='1', command=lambda: get_input(entry, '1'))
button1.grid(row=3, column=0, pady=5)
button2 = myButton(text='2', command=lambda: get_input(entry, '2'))
button2.grid(row=3, column=1, pady=5)
button3 = myButton(text='3', command=lambda: get_input(entry, '3'))
button3.grid(row=3, column=2, pady=5)
button12 = myButton(text='*', command=lambda: get_input(entry, '*'))
button12.grid(row=3, column=3, pady=5)
button0 = myButton(text='0', command=lambda: get_input(entry, '0'))
button0.grid(row=4, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button18 = myButton(text='%', command=lambda: get_input(entry, '%'))
button18.grid(row=4, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button13 = myButton(text='.', command=lambda: get_input(entry, '.'))
button13.grid(row=4, column=2, pady=5)
button14 = Button(root, text='/', bg=button_bg, padx=10, pady=3,
command=lambda: get_input(entry, '/'))
button14.grid(row=4, column=3, pady=5)
button15 = Button(root, text='<-', bg=button_bg, padx=10, pady=3,
command=lambda: backspace(entry), activebackground=button_active_bg)
button15.grid(row=5, column=0, pady=5)
button16 = Button(root, text='C', bg=button_bg, padx=10, pady=3,
command=lambda: clear(entry), activebackground=button_active_bg)
button16.grid(row=5, column=1, pady=5)
button17 = Button(root, text='=', bg=button_bg, padx=10, pady=3,
command=lambda: calc(entry), activebackground=button_active_bg)
button17.grid(row=5, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)
button19 = myButton(text='sin', command=lambda: get_input(entry, 'sin'))
button19.grid(row=6, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button20 = myButton(text='cos', command=lambda: get_input(entry, 'cos'))
button20.grid(row=6, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button21 = myButton(text='tan', command=lambda: get_input(entry, 'tan'))
button21.grid(row=6, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)
button22 = myButton(text='(', command=lambda: get_input(entry, '('))
button22.grid(row=7, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button23 = myButton(text=')', command=lambda: get_input(entry, ')'))
button23.grid(row=7, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)
button24 = myButton(text='&', command=lambda: get_input(entry, '&'))
button24.grid(row=7, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)
root.mainloop()
if __name__ == '__main__':
cal()
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现