├── screenshot ├── sp20161010_212107.png ├── sp20161010_214051.png └── sp20161010_214714.png ├── Calculator ├── pushbutton.cpp ├── Calculator.pro ├── pushbutton.h ├── README.md ├── main.cpp ├── mainwindow.h ├── Expression.h ├── MathEx.h ├── MathEx.cpp ├── metacharacter.h ├── mainwindow.cpp └── Expression.cpp ├── math_expr_eval ├── main.cpp ├── README.md ├── Expression.h ├── MathEx.h ├── MathEx.cpp ├── metacharacter.h └── Expression.cpp ├── README.md ├── .gitignore └── LICENSE /screenshot/sp20161010_212107.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz1001/math-expr-eval/HEAD/screenshot/sp20161010_212107.png -------------------------------------------------------------------------------- /screenshot/sp20161010_214051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz1001/math-expr-eval/HEAD/screenshot/sp20161010_214051.png -------------------------------------------------------------------------------- /screenshot/sp20161010_214714.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz1001/math-expr-eval/HEAD/screenshot/sp20161010_214714.png -------------------------------------------------------------------------------- /Calculator/pushbutton.cpp: -------------------------------------------------------------------------------- 1 | #include "pushbutton.h" 2 | 3 | PushButton::PushButton(const QString &text, QWidget *parent) 4 | :QPushButton(text, parent) 5 | { 6 | connect(this, &QPushButton::clicked, this, &PushButton::onClicked); 7 | } 8 | 9 | void PushButton::onClicked() 10 | { 11 | emit clicked(this); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /math_expr_eval/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Expression.h" //导入Expression头文件 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | while (1) 9 | { 10 | string str; 11 | cin >> str; 12 | Expression e(str, 5); //传入输入的表达式,小数点保留5位 13 | try 14 | { 15 | cout << e.getResult() << endl; //读取计算结果 16 | } 17 | catch (runtime_error err) //捕获异常 18 | { 19 | cerr << err.what() << endl; 20 | } 21 | } 22 | cin.get(); 23 | cin.get(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /Calculator/Calculator.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-05-05T20:07:59 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = Calculator 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | Expression.cpp \ 18 | MathEx.cpp \ 19 | pushbutton.cpp 20 | 21 | HEADERS += mainwindow.h \ 22 | Expression.h \ 23 | MathEx.h \ 24 | metacharacter.h \ 25 | pushbutton.h 26 | 27 | CONFIG += c++11 28 | -------------------------------------------------------------------------------- /Calculator/pushbutton.h: -------------------------------------------------------------------------------- 1 | /** 2 | * QPushButton子类,捕获原不带参数的clicked信号并重新发射clicked(PushButton*)信号, 3 | * 便于槽函数得知发射信号按钮. 4 | */ 5 | #ifndef PUSHBUTTON_H 6 | #define PUSHBUTTON_H 7 | #include 8 | 9 | class PushButton : public QPushButton 10 | { 11 | Q_OBJECT 12 | public: 13 | PushButton(const QString &text, QWidget *parent = 0); 14 | /* 15 | * 不允许拷贝和赋值 16 | */ 17 | PushButton(const PushButton&) = delete; 18 | PushButton& operator=(const PushButton&) = delete; 19 | 20 | signals: 21 | void clicked(PushButton *pushButton); 22 | 23 | private slots: 24 | void onClicked(); 25 | }; 26 | 27 | #endif // PUSHBUTTON_H 28 | -------------------------------------------------------------------------------- /Calculator/README.md: -------------------------------------------------------------------------------- 1 | ## 表达式运算计算器 2 | 本项目是基于数学表达式计算库开发的一个计算器,界面通过Qt实现。 3 | ## 依赖 4 | * qmake >= 5.3 5 | 6 | ## 编译安装 7 | 1. 确保依赖已满足 8 | 2. 编译安装: 9 | ``` 10 | $ mkdir build 11 | $ cd build 12 | $ qmake .. 13 | $ make 14 | $ sudo make install 15 | ``` 16 | 17 | ## 运行界面 18 | ![](https://github.com/xyz1001/math-expr-eval/blob/master/screenshot/sp20161010_212107.png)![](https://github.com/xyz1001/math-expr-eval/blob/master/screenshot/sp20161010_214051.png) 19 | 20 | ## 使用说明 21 | - `↑`键用于切换`sin` `cos` `tan` `lg`为`arcsin` `arccos` `arctan` `ln` 22 | - `←`键用于删除前一个输入的数字或运算符 23 | - `C`键清空输入框 24 | - `Ans`用于输入上次计算结果 25 | 26 | ## TODO 27 | 1. 键盘输入 28 | 2. 窗体美化 29 | 3. 按键的可用状态动态改变 30 | 4. 历史记录功能 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 复杂数学表达式求值 2 | 本项目为一个利用C++对常用复杂数学表达式进行求值的算法类。附带一个利用这个算法类写的计算器,通过Qt实现界面。 3 | 4 | # 支持的运算符 5 | 支持常见的运算符,加减乘除(`+-*/`),开方(`#`),乘方(`^`),模(`%`),百分比(`%`),度(`` ` ``反引号) ,阶乘(`!`),三角函数(`sin, cos, tan, arcsin, arccos, arctan`),对数(`log,ln,lg`)等。其中开平方支持省略根指数2。 6 | 括号内为代码中使用的运算符符号,输入表达式时需要将表达式内对应符号转为括号内对应符号。即`√` `°` `×` `÷`等符号是非法的,需转换为`#` `` ` `` `*` `/` 7 | 8 | # 运算优先级 9 | 1. 如果有括号就先算括号内后算括号外,同一级运算顺序是从左到右,不区分大中小括号; 10 | 2. 百分号和角度符号优先级最高; 11 | 3. 三角函数和对数运算优先级相同,小于上一条; 12 | 4. 阶乘和开平方优先级相同,小于上一条; 13 | 5. 乘方和开多次方优先级相同,小于上一条; 14 | 6. 模运算与乘除优先级相同,小于上一条; 15 | 7. 负号,加减运算优先级最低; 16 | 17 | 推荐多使用括号,避免因运算符优先级导致的问题 18 | 19 | ## 例1 20 | 表达式 | 计算步骤 21 | -----------------------|-------------------- 22 | `` 8+5*sin90`!*2^#4``|先将角度转为弧度 23 | `=8+5*sin1.57076!*2^#4`|计算sin 24 | `=8+5*1!*2^#4`|计算阶乘 25 | `=8+5*1*2^#4`|计算开方 26 | `=8+5*1*2^2`|计算乘方 27 | `=8+5*1*4`|计算第一个乘法 28 | `=8+5*4`|计算第二个乘法 29 | `=8+20`|计算加法 30 | `=28`| 31 | 32 | ## 例2 33 | 表达式 | 计算步骤 34 | ------------------------|-------------------- 35 | `-lg10+lg1000%*#4!`|百分数化为小数 36 | `=-lg10+lg10*#4!`|计算lg 37 | `=-1+1*#4!`|计算开平方 38 | `=-1+1*2!`|计算乘方 39 | `=-1+1*2`|计算乘法 40 | `=-1+2`|计算负号 41 | `=-1+2`|计算加法 42 | `=1`| 43 | 44 | ![计算结果](https://github.com/xyz1001/Complex-mathematical-expressions/raw/master/screenshot/sp20161010_214714.png) 45 | 46 | # USAGE 47 | [数学表达式求值算法类的使用](https://github.com/xyz1001/Complex-mathematical-expressions/tree/master/MathExpressionCalculator) 48 | 49 | [计算器的介绍和使用](https://github.com/xyz1001/Complex-mathematical-expressions/tree/master/Calculator) 50 | 51 | ## License 52 | under GPLv3 53 | -------------------------------------------------------------------------------- /math_expr_eval/README.md: -------------------------------------------------------------------------------- 1 | # 数学表达式求值 2 | ## 下载和使用 3 | 1. `git clone git@github.com:xyz1001/math-expr-eval.git` 4 | 2. 复制expression文件夹下除`main.cpp`文件外其他文件至你的代码目录并将其添加至工程中 5 | 3. 定义Expression对象并通过`string getResult()`函数获取计算结果,参考`main.cpp`内容 6 | 7 | ## 运行示例 8 | - linux 9 | 1. `git clone git@github.com:xyz1001/math-expr-eval.git` 10 | 2. `cd math-expr-eval/math-expr-eval/` 11 | 3. `make` 12 | 4. `chmod u+x main` 13 | 5. `./main` 14 | 15 | - windows 16 | 1. `git clone git@github.com:xyz1001/math-expr-eval.git` 17 | 2. 通过IDE编译运行即可 18 | 19 | 输入合法的数学表达式即可输出表达式的计算结果 20 | 21 | ![示例界面](https://github.com/xyz1001/math-expr-eval/blob/master/screenshot/sp20161010_214714.png) 22 | 23 | ## 说明 24 | - 实现算法为将表达式转换为逆波兰式(后缀表达式)计算 25 | 26 | - `Expression`类为表达式解析类, `MathEx`类定义了各运算符的运算规则, `metacharacter`头文件中定义了常见运算符的属性 27 | 28 | - 数学表达式中所使用的符号必须与`metacharacter`头文件中`METACHARACTERS`表规定的一致,调用表达式计算类时一定要先将运算符转换为代码中对应的字符,具体对应如下 29 | 30 | 标准运算符|代码符号|含义 31 | ---------------|-----------|------ 32 | `+`|`+`|加法 33 | `-`|`-`|减法 34 | `×`|`*`|乘法 35 | `÷`|`/`|除法 36 | `MOD`|`%`|求余 37 | `%`|`%`或`>`|百分数 38 | 上标|`^`|幂 39 | `√ ̄`|`#`|开方 40 | `√ ̄`|`<`|开平方 41 | `!`|`!`|阶乘 42 | `sin`|`sin`|正弦 43 | `cos`|`cos`|余弦 44 | `tan`|`tan`|正切 45 | `arcsin`|`arcsin`|反正弦 46 | `arccos`|`arccos`|反余弦 47 | `arctan`|`arctan`|反正切 48 | `lg`|`lg`或`log`|常用对数 49 | `ln`|`ln`|自然对数 50 | `°`|`` ` ``|角度符号 51 | 52 | - 代码中使用`double`存储数字,精度有限,不宜进行高精度和大数计算 53 | 54 | - 返回值为带小数部分的`string`类型,应视情况去除尾部多余的`0`和小数点 55 | 56 | - `Expression`类默认保留5位小数,可通过构造函数第二个参数进行设置 57 | 58 | ## 注意 59 | 1. 不支持负数的开方,即使是根指数为奇数的分数. 60 | 2. 定义了常见的表达式错误及运算错误,注意捕获异常 61 | 62 | ## TODO 63 | 1. 对高精度运算的支持 64 | 2. 对大数运算的支持 65 | 3. 小数点位数的动态确定 66 | 4. 对`×÷`等符号的预转换 67 | 3. 返回值尾部多余`0`的去除 68 | -------------------------------------------------------------------------------- /Calculator/main.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * main.cpp - 计算器 3 | * 4 | * Copyright (c) 2015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 支持计算数学表达式的计算器,界面通过Qt5实现 8 | * 9 | * Version:0.1 10 | * Copyright:Zix 11 | * Author:Zix 12 | * Date:2015/07/05 13 | * modification history: 14 | * 1.完成基本布局 15 | * 16 | * Version:0.2 17 | * Copyright:Zix 18 | * Author:Zix 19 | * Date:2015/08/05 20 | * modification history: 21 | * 1.实现数字键和运算符键的点击响应 22 | * 23 | * Version:0.3 24 | * Copyright:Zix 25 | * Author:Zix 26 | * Date:2015/09/24 27 | * modification history: 28 | * 1.实现功能键的响应及加减乘除和括号的运算 29 | * 30 | * Version:0.4 31 | * Copyright:Zix 32 | * Author:Zix 33 | * Date:2015/09/25 34 | * modification history: 35 | * 1.修复回删计算已完成的表达式时未删除等号前运算符建可用的BUG 36 | * 2.除法错误 37 | * 3.实现Ans键功能并去除结果中尾部多余的0和小数点 38 | * TODO: 39 | * 1.界面修改 40 | * 2.键盘不响应无效按键 41 | * 42 | * Version:1.0 43 | * Copyright:Zix 44 | * Author:Zix 45 | * Date:2016/05/14 46 | * modification history: 47 | * 1.更换表达式计算类,支持复杂数学表达式计算和更多运算符 48 | * 2.除法错误 49 | * 3.实现Ans键功能并去除结果中尾部多余的0和小数点 50 | * 51 | * Version:1.1 52 | * Copyright:Zix 53 | * Author:Zix 54 | * Date:2016/10/09 55 | * modification history: 56 | * 1.界面重新设计,更美观适用 57 | * 2.将对运算符的定义移至新头文件metacharacter.h中,提高扩展性和可读性 58 | * 3.重写对按键的输入响应函数,大幅度减少冗余代码 59 | * 4.移除按键的可用状态动态改变功能 60 | * 5.添加对角度符号的支持 61 | * 62 | * Version:1.2 63 | * Copyright:Zix 64 | * Author:Zix 65 | * Date:2016/10/10 66 | * modification history: 67 | * 1.重新实现 68 | * 2.将对运算符的定义移至新头文件metacharacter.h中,提高扩展性和可读性 69 | * 3.表达式输入框和结果框分离 70 | * 4.表达式计算库错误修复及优化 71 | * 5.添加注释 72 | * 73 | * Version:1.2 74 | * Copyright:Zix 75 | * Author:Zix 76 | * Date:2016/10/11 77 | * modification history: 78 | * 1.编写README.md 79 | *****************************************************************************/ 80 | #include "mainwindow.h" 81 | #include 82 | 83 | int main(int argc, char *argv[]) 84 | { 85 | QApplication a(argc, argv); 86 | MainWindow w; 87 | w.show(); 88 | 89 | return a.exec(); 90 | } 91 | -------------------------------------------------------------------------------- /Calculator/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "Expression.h" 16 | #include "metacharacter.h" 17 | #include "pushbutton.h" 18 | 19 | /* 20 | * 定义按钮上的显示字符 21 | */ 22 | const string SHIFT = "↑"; 23 | const string BACKSPACE = "←"; 24 | const string CLEAR = "C"; 25 | const string ANS = "Ans"; 26 | //按钮布局 27 | const QVector> BUTTONS{{SIN, COS, TAN, LG}, 28 | {"", "", "", LEFT_BRACKET, RIGHT_BRACKET}, 29 | {SEVEN, EIGHT, NINE, ADD, EXTRACT_ROOT}, 30 | {FOUR, FIVE, SIX, MINUS, POW}, 31 | {ONE, TWO, THREE, MULTIPLY, MOD_PERCENT}, 32 | {DEGREE, ZERO, POINT, DIVIDE, FACTORIAL}}; 33 | //shift转换按钮对应表 34 | const QMap SHIFT_TABLE{{SIN, ARCSIN}, 35 | {COS,ARCCOS}, 36 | {TAN, ARCTAN}, 37 | {LG, LN}}; 38 | 39 | class MainWindow : public QMainWindow 40 | { 41 | Q_OBJECT 42 | 43 | public: 44 | MainWindow(QWidget *parent = 0); 45 | ~MainWindow(); 46 | QString cal(QString s); //计算,传入表达式s,返回表达式值 47 | Expression *expression; //表达式计算对象 48 | private: 49 | QWidget *CentralWidget; 50 | 51 | QGridLayout *buttonsLayout; 52 | QGridLayout *MainLayout; 53 | 54 | QVector buttons; //按钮集合 55 | QVector functionKeyButtons; //功能键集合 56 | 57 | QPushButton *functionKeyButtonBackspace; //回退一个字符 58 | QPushButton *functionKeyButtonClear; //清空 59 | QPushButton *functionKeyButtonAns; //上次计算结果 60 | QPushButton *functionKeyButtonShift; //shift按钮 61 | QPushButton *equalButton; //等于按钮 62 | QLineEdit *inputText; //表达式输入框 63 | QLabel *equalLabel; //等于号 64 | QLineEdit *resultText; //计算结果显示框 65 | 66 | QStack historySize; 67 | QString Ans = "0"; //保存上次计算结果 68 | bool isShifting = false; //shift键按下状态标记 69 | bool calcFinished = true; //计算已完成状态标记(与正在输入表达式状态对应) 70 | 71 | /* 72 | * 将表达式中特殊字符转换为规范的计算字符 73 | * 本程序转换规则有: 74 | * 显示字符 计算字符 75 | * × * 76 | * ÷ / 77 | * √ # 78 | * ° ` 79 | */ 80 | string transformStdExpression(QString expression); 81 | private slots: 82 | void setInputText(PushButton *pushButton); //按钮按下时设置输入框,参数为按钮指针 83 | void onEqualClicked(); //等于按钮按下 84 | void onBackspaceClicked(); //删除按钮按下 85 | void onClearClicked(); //清空按钮按下 86 | void onAnsClicked(); //上次计算结果按钮按下 87 | void onShiftClicked(); //shift按钮按下 88 | 89 | }; 90 | 91 | #endif // MAINWINDOW_H 92 | -------------------------------------------------------------------------------- /Calculator/Expression.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Expression.h - 表达式解析类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 通过对传入的数学表达式进行解析并通过转换为逆波兰式进行求值 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/5/13 12 | * modification history: 13 | * 1.基本支持表达式的计算 14 | * 15 | * Copyright:Zix 16 | * Author:Zix 17 | * Date:2016/10/09 18 | * modification history: 19 | * 1.新增对角度符号的支持 20 | * 2.提取运算符定义至新头文件metacharacter.h中 21 | * 3.根据小数位设置对结果进行处理 22 | * 23 | * Copyright:Zix 24 | * Author:Zix 25 | * Date:2016/10/10 26 | * modification history: 27 | * 1.优化对具有二义性符号(百分号,开方)的处理 28 | * 2.提取符号定义至新头文件metacharacter.h中 29 | * 30 | * 31 | ******************************************************************************/ 32 | #ifndef EXPRESSION_H 33 | #define EXPRESSION_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "MathEx.h" 40 | #include "metacharacter.h" 41 | 42 | using namespace std; 43 | 44 | //异常命名空间 45 | namespace ExpressionError 46 | { 47 | //非法字符 48 | const string ILLEGAL_CHARACTER_ERROR = "非法字符: "; 49 | //括号不匹配 50 | const string ILLEGAL_BRACKET_ERROR = "括号不匹配"; 51 | //缺失操作数 52 | const string MISSING_OPERAND_ERROR = "缺少操作数"; 53 | //多余的操作数 54 | const string MISSING_OPERATOR_ERROR = "缺少运算符"; 55 | //百分号前只能为数字或括号包围的表达式 56 | const string PERCENT_OPERATOR_ERROR = "百分号前只能为数字或括号包围的表达式"; 57 | //角度符号前只能为数字或括号包围的表达式 58 | const string DEGREE_OPERATOR_ERROR = "角度符号前只能为数字或括号包围的表达式"; 59 | //在优先级大于开平方运算符的运算符之后的开平方运算需要用括号包围 60 | const string SQUARE_ROOT_ERROR = "开平方运算需要用括号包围"; 61 | //未知异常 62 | const string UNKNOWN_ERROR = "未知错误"; 63 | } 64 | 65 | class Expression 66 | { 67 | private: 68 | //数学计算 69 | MathEx mathEx; 70 | //原始字符串 71 | string raw_exp; 72 | //拆分后的表达式元素列表 73 | list exp; 74 | //操作符栈 75 | stack op; 76 | //数字栈 77 | stack number; 78 | //表达式的值 79 | double result = 0; 80 | 81 | //对表达式进行字符合法性的初步检测 82 | bool simpleCheck(); 83 | //拆分表达式 84 | bool split(); 85 | //负号检测及处理 86 | void negativeOperatorPreprocessing(); 87 | //开方负号检测及处理 88 | void sqrtOperatorPreprocessing(); 89 | //百分号/求余符号检测及处理 90 | void percentOperatorPreprocessing(); 91 | //度符号检测及处理 92 | void degreeOperatorPreprocessing(); 93 | //不同括号检测及处理 94 | void bracketPreprocessing(); 95 | //特殊运算符检测及处理 96 | void preprocessing(); 97 | //出栈运算符运算 98 | void operation(); 99 | //转换成后缀表达式,边转换边求值 100 | void transToPostfix(); 101 | //单目运算符运算 102 | void calc(Metacharacter mc, double &op1); 103 | //双目运算符运算 104 | void calc(Metacharacter mc, double &op1, double &op2); 105 | public: 106 | //str: 算术表达式 precision: 保留的小数点位数 107 | Expression(string str, int precision = 5); 108 | ~Expression(); 109 | //获取计算结果 110 | string getResult(); 111 | }; 112 | 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /math_expr_eval/Expression.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Expression.h - 表达式解析类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 通过对传入的数学表达式进行解析并通过转换为逆波兰式进行求值 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/5/13 12 | * modification history: 13 | * 1.基本支持表达式的计算 14 | * 15 | * Copyright:Zix 16 | * Author:Zix 17 | * Date:2016/10/09 18 | * modification history: 19 | * 1.新增对角度符号的支持 20 | * 2.提取运算符定义至新头文件metacharacter.h中 21 | * 3.根据小数位设置对结果进行处理 22 | * 23 | * Copyright:Zix 24 | * Author:Zix 25 | * Date:2016/10/10 26 | * modification history: 27 | * 1.优化对具有二义性符号(百分号,开方)的处理 28 | * 2.提取符号定义至新头文件metacharacter.h中 29 | * 30 | * 31 | ******************************************************************************/ 32 | #ifndef EXPRESSION_H 33 | #define EXPRESSION_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "MathEx.h" 40 | #include "metacharacter.h" 41 | 42 | using namespace std; 43 | 44 | //异常命名空间 45 | namespace ExpressionError 46 | { 47 | //非法字符 48 | const string ILLEGAL_CHARACTER_ERROR = "非法字符: "; 49 | //括号不匹配 50 | const string ILLEGAL_BRACKET_ERROR = "括号不匹配"; 51 | //缺失操作数 52 | const string MISSING_OPERAND_ERROR = "缺少操作数"; 53 | //多余的操作数 54 | const string MISSING_OPERATOR_ERROR = "缺少运算符"; 55 | //百分号前只能为数字或括号包围的表达式 56 | const string PERCENT_OPERATOR_ERROR = "百分号前只能为数字或括号包围的表达式"; 57 | //角度符号前只能为数字或括号包围的表达式 58 | const string DEGREE_OPERATOR_ERROR = "角度符号前只能为数字或括号包围的表达式"; 59 | //在优先级大于开平方运算符的运算符之后的开平方运算需要用括号包围 60 | const string SQUARE_ROOT_ERROR = "开平方运算需要用括号包围"; 61 | //未知异常 62 | const string UNKNOWN_ERROR = "未知错误"; 63 | } 64 | 65 | class Expression 66 | { 67 | private: 68 | //数学计算 69 | MathEx mathEx; 70 | //原始字符串 71 | string raw_exp; 72 | //拆分后的表达式元素列表 73 | list exp; 74 | //操作符栈 75 | stack op; 76 | //数字栈 77 | stack number; 78 | //表达式的值 79 | double result = 0; 80 | 81 | //对表达式进行字符合法性的初步检测 82 | bool simpleCheck(); 83 | //拆分表达式 84 | bool split(); 85 | //负号检测及处理 86 | void negativeOperatorPreprocessing(); 87 | //开方负号检测及处理 88 | void sqrtOperatorPreprocessing(); 89 | //百分号/求余符号检测及处理 90 | void percentOperatorPreprocessing(); 91 | //度符号检测及处理 92 | void degreeOperatorPreprocessing(); 93 | //不同括号检测及处理 94 | void bracketPreprocessing(); 95 | //特殊运算符检测及处理 96 | void preprocessing(); 97 | //出栈运算符运算 98 | void operation(); 99 | //转换成后缀表达式,边转换边求值 100 | void transToPostfix(); 101 | //单目运算符运算 102 | void calc(Metacharacter mc, double &op1); 103 | //双目运算符运算 104 | void calc(Metacharacter mc, double &op1, double &op2); 105 | public: 106 | //str: 算术表达式 precision: 保留的小数点位数 107 | Expression(string str, int precision = 5); 108 | ~Expression(); 109 | //获取计算结果 110 | string getResult(); 111 | }; 112 | 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /Calculator/MathEx.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * MathEx.h - 数学计算类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 对cmath类的进一步封装及添加,实现对错误的捕获 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/5/13 12 | * modification history: 13 | * 1.支持常见运算符的运算 14 | * 15 | * Copyright:Zix 16 | * Author:Zix 17 | * Date:2016/10/09 18 | * modification history: 19 | * 1.新增对角度符号的运算,将其转换为弧度 20 | * 2.新增对结果进行保留设定小数位的函数getRound(); 21 | * 22 | * Copyright:Zix 23 | * Author:Zix 24 | * Date:2016/10/10 25 | * modification history: 26 | * 1.新增百分号运算和开平方运算 27 | * 28 | ******************************************************************************/ 29 | #ifndef MATHEX_H 30 | #define MATHEX_H 31 | 32 | #include 33 | 34 | using namespace std; 35 | 36 | namespace MathExError 37 | { 38 | //除数为0 39 | const string DIVISOR_ERROR = "除数不能为0"; 40 | //被开方数不能小于0 41 | const string RADICAND_ERROR = "被开方数不能小于0"; 42 | //负数不存在平方根 43 | const string EXTRACT_ROOT_ERROR = "负数不存在平方根"; 44 | //模运算两数不全为整数 45 | const string MOD_ERROR = "模运算两操作数需均为整数"; 46 | //模数为0 47 | const string MODULUS_ERROR = "模数不能为0"; 48 | //0的幂指数为非正数 49 | const string POW_ERROR = "0的幂指数不能为非正数"; 50 | //非自然数的阶乘 51 | const string FACTORIAL_ERROR = "阶乘数需为自然数"; 52 | //正切函数的自变量取值错误 53 | const string TAN_ERROR = "正切函数自变量取值不能为kπ+π/2"; 54 | //反正弦,余弦函数自变量取值范围[-1,1] 55 | const string ARCSIN_ARCCOS_ERROR = "反正弦和反余弦函数自变量绝对值不能大于1"; 56 | //对数的真数为非正数 57 | const string ANTILOGARITHM_ERROR = "对数的真数不能为非正数"; 58 | //未知异常 59 | const string UNKNOWN_ERROR = "未知异常"; 60 | } 61 | 62 | const double PI = 3.14159265358979323846; 63 | 64 | class MathEx 65 | { 66 | private: 67 | double EPS = 1e-4; //小数精度 68 | public: 69 | MathEx(); 70 | ~MathEx(); 71 | 72 | void set_eps(int e); //设置精度,e为小数点位数 73 | double getRound(double d) const; //根据精度四舍五入 74 | 75 | //加法运算 76 | double op_add(const double &op1, const double &op2) const; 77 | //减法运算 78 | double op_subtract(const double &op1, const double &op2) const; 79 | //乘法运算 80 | double op_multiply(const double &op1, const double &op2) const; 81 | //除法运算 82 | double op_divide(const double &op1, const double &op2) const; 83 | //模运算 84 | double op_mod(const double &op1, const double &op2) const; 85 | //乘方运算 86 | double op_pow(const double &op1, const double &op2) const; 87 | //开平方运算 88 | double op_square_root(const double &op) const; 89 | //开方运算 90 | double op_extract_root(const double &op1, const double &op2) const; 91 | //阶乘运算 92 | double op_factorial(const double &op) const; 93 | //阶乘运算 94 | double op_percent(const double &op) const; 95 | //角度转弧度 96 | double op_degree_to_radian(const double &op) const; 97 | //正弦运算,op为弧度 98 | double op_sin(const double &op) const; 99 | //余弦运算,op为弧度 100 | double op_cos(const double &op) const; 101 | //正切运算,op为弧度 102 | double op_tan(const double &op) const; 103 | //反正弦运算,返回值为弧度 104 | double op_arcsin(const double &op) const; 105 | //反余弦运算,返回值为弧度 106 | double op_arccos(const double &op) const; 107 | //反正切运算,返回值为弧度 108 | double op_arctan(const double &op) const; 109 | //常用对数,底数为10 110 | double op_lg(const double &op) const; 111 | //自然对数,底数为e 112 | double op_ln(const double &op) const; 113 | }; 114 | 115 | #endif // !MATHEX_H 116 | -------------------------------------------------------------------------------- /math_expr_eval/MathEx.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * MathEx.h - 数学计算类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 对cmath类的进一步封装及添加,实现对错误的捕获 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/5/13 12 | * modification history: 13 | * 1.支持常见运算符的运算 14 | * 15 | * Copyright:Zix 16 | * Author:Zix 17 | * Date:2016/10/09 18 | * modification history: 19 | * 1.新增对角度符号的运算,将其转换为弧度 20 | * 2.新增对结果进行保留设定小数位的函数getRound(); 21 | * 22 | * Copyright:Zix 23 | * Author:Zix 24 | * Date:2016/10/10 25 | * modification history: 26 | * 1.新增百分号运算和开平方运算 27 | * 28 | ******************************************************************************/ 29 | #ifndef MATHEX_H 30 | #define MATHEX_H 31 | 32 | #include 33 | 34 | using namespace std; 35 | 36 | namespace MathExError 37 | { 38 | //除数为0 39 | const string DIVISOR_ERROR = "除数不能为0"; 40 | //被开方数不能小于0 41 | const string RADICAND_ERROR = "被开方数不能小于0"; 42 | //负数不存在平方根 43 | const string EXTRACT_ROOT_ERROR = "负数不存在平方根"; 44 | //模运算两数不全为整数 45 | const string MOD_ERROR = "模运算两操作数需均为整数"; 46 | //模数为0 47 | const string MODULUS_ERROR = "模数不能为0"; 48 | //0的幂指数为非正数 49 | const string POW_ERROR = "0的幂指数不能为非正数"; 50 | //非自然数的阶乘 51 | const string FACTORIAL_ERROR = "阶乘数需为自然数"; 52 | //正切函数的自变量取值错误 53 | const string TAN_ERROR = "正切函数自变量取值不能为kπ+π/2"; 54 | //反正弦,余弦函数自变量取值范围[-1,1] 55 | const string ARCSIN_ARCCOS_ERROR = "反正弦和反余弦函数自变量绝对值不能大于1"; 56 | //对数的真数为非正数 57 | const string ANTILOGARITHM_ERROR = "对数的真数不能为非正数"; 58 | //未知异常 59 | const string UNKNOWN_ERROR = "未知异常"; 60 | } 61 | 62 | const double PI = 3.14159265358979323846; 63 | 64 | class MathEx 65 | { 66 | private: 67 | double EPS = 1e-4; //小数精度 68 | public: 69 | MathEx(); 70 | ~MathEx(); 71 | 72 | void set_eps(int e); //设置精度,e为小数点位数 73 | double getRound(double d) const; //根据精度四舍五入 74 | 75 | //加法运算 76 | double op_add(const double &op1, const double &op2) const; 77 | //减法运算 78 | double op_subtract(const double &op1, const double &op2) const; 79 | //乘法运算 80 | double op_multiply(const double &op1, const double &op2) const; 81 | //除法运算 82 | double op_divide(const double &op1, const double &op2) const; 83 | //模运算 84 | double op_mod(const double &op1, const double &op2) const; 85 | //乘方运算 86 | double op_pow(const double &op1, const double &op2) const; 87 | //开平方运算 88 | double op_square_root(const double &op) const; 89 | //开方运算 90 | double op_extract_root(const double &op1, const double &op2) const; 91 | //阶乘运算 92 | double op_factorial(const double &op) const; 93 | //阶乘运算 94 | double op_percent(const double &op) const; 95 | //角度转弧度 96 | double op_degree_to_radian(const double &op) const; 97 | //正弦运算,op为弧度 98 | double op_sin(const double &op) const; 99 | //余弦运算,op为弧度 100 | double op_cos(const double &op) const; 101 | //正切运算,op为弧度 102 | double op_tan(const double &op) const; 103 | //反正弦运算,返回值为弧度 104 | double op_arcsin(const double &op) const; 105 | //反余弦运算,返回值为弧度 106 | double op_arccos(const double &op) const; 107 | //反正切运算,返回值为弧度 108 | double op_arctan(const double &op) const; 109 | //常用对数,底数为10 110 | double op_lg(const double &op) const; 111 | //自然对数,底数为e 112 | double op_ln(const double &op) const; 113 | }; 114 | 115 | #endif // !MATHEX_H 116 | -------------------------------------------------------------------------------- /Calculator/MathEx.cpp: -------------------------------------------------------------------------------- 1 | #include "MathEx.h" 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | MathEx::MathEx() 8 | { 9 | } 10 | 11 | 12 | MathEx::~MathEx() 13 | { 14 | } 15 | 16 | void MathEx::set_eps(int e) 17 | { 18 | EPS = pow(10, -e); 19 | } 20 | 21 | double MathEx::getRound(double d) const 22 | { 23 | double abs_d = abs(d); 24 | int sign = 1; //标记d的正负 25 | if(d<0) 26 | sign = -1; 27 | return static_cast(abs_d/EPS+0.5)*EPS*sign; //四舍五入 28 | } 29 | 30 | double MathEx::op_add(const double &op1, const double &op2) const 31 | { 32 | return op1 + op2; 33 | } 34 | 35 | double MathEx::op_subtract(const double &op1, const double &op2) const 36 | { 37 | return op1 - op2; 38 | } 39 | 40 | double MathEx::op_multiply(const double &op1, const double &op2) const 41 | { 42 | return op1 * op2; 43 | } 44 | 45 | double MathEx::op_divide(const double &op1, const double &op2) const 46 | { 47 | if (abs(op2) < EPS) //除数为0 48 | throw runtime_error(MathExError::DIVISOR_ERROR); 49 | return op1 / op2; 50 | } 51 | 52 | double MathEx::op_mod(const double &op1, const double &op2) const 53 | { 54 | //操作数不是整数 55 | if (abs(op1 - static_cast(op1)) > EPS || abs(op2 - static_cast(op2)) > EPS) 56 | throw runtime_error(MathExError::MOD_ERROR); 57 | //模数为0 58 | if (abs(op2) <= EPS) 59 | throw runtime_error(MathExError::MODULUS_ERROR); 60 | return static_cast(op1) % static_cast(op2); 61 | } 62 | 63 | double MathEx::op_pow(const double &op1, const double &op2) const 64 | { 65 | //操作数不大于0 66 | if (abs(op1) < EPS&&op2 < EPS) 67 | throw runtime_error(MathExError::POW_ERROR); 68 | return pow(op1, op2); 69 | } 70 | 71 | double MathEx::op_square_root(const double &op) const 72 | { 73 | //被开方数为负 74 | if (op < 0) 75 | throw runtime_error(MathExError::RADICAND_ERROR); 76 | return sqrt(op); 77 | } 78 | 79 | double MathEx::op_extract_root(const double &op1, const double &op2) const 80 | { 81 | //被开方数为负 82 | if (op2 < 0) 83 | throw runtime_error(MathExError::RADICAND_ERROR); 84 | return pow(op2, 1 / op1); 85 | } 86 | 87 | double MathEx::op_factorial(const double &op) const 88 | { 89 | int n = static_cast(op), sum = n; 90 | if (op<0 || abs(op - n) > EPS) //阶乘数不为正整数 91 | throw runtime_error(MathExError::FACTORIAL_ERROR); 92 | if (n == 0 || n == 1) 93 | return 1; 94 | while (--n) 95 | sum *= n; 96 | return sum; 97 | } 98 | 99 | double MathEx::op_percent(const double &op) const 100 | { 101 | return op/100; 102 | } 103 | 104 | double MathEx::op_degree_to_radian(const double &op) const 105 | { 106 | return op * PI / 180; 107 | } 108 | 109 | double MathEx::op_sin(const double &op) const 110 | { 111 | return sin(op); 112 | } 113 | 114 | double MathEx::op_cos(const double &op) const 115 | { 116 | return cos(op); 117 | } 118 | 119 | double MathEx::op_tan(const double &op) const 120 | { 121 | double angle = op * 180 / PI; 122 | int i_angle = static_cast(angle); 123 | if (angle - i_angle <= EPS && (i_angle + 90) % 180 == 0) //正切值不为kπ+π/2 124 | throw runtime_error(MathExError::TAN_ERROR); 125 | return tan(op); 126 | } 127 | 128 | double MathEx::op_arcsin(const double &op) const 129 | { 130 | if (abs(op) > 1) //反正弦的定义域为[-1,1] 131 | throw runtime_error(MathExError::ARCSIN_ARCCOS_ERROR); 132 | return asin(op); 133 | } 134 | 135 | double MathEx::op_arccos(const double &op) const 136 | { 137 | if (abs(op) > 1) //反余弦的定义域为[-1,1] 138 | throw runtime_error(MathExError::ARCSIN_ARCCOS_ERROR); 139 | return acos(op); 140 | } 141 | 142 | double MathEx::op_arctan(const double &op) const 143 | { 144 | return atan(op); 145 | } 146 | 147 | double MathEx::op_lg(const double &op) const 148 | { 149 | if (op < EPS) //对数定义域为(0,正无穷) 150 | throw runtime_error(MathExError::ANTILOGARITHM_ERROR); 151 | return log10(op); 152 | } 153 | 154 | double MathEx::op_ln(const double &op) const 155 | { 156 | if (op < EPS) 157 | throw runtime_error(MathExError::ANTILOGARITHM_ERROR); 158 | return log(op); 159 | } 160 | -------------------------------------------------------------------------------- /math_expr_eval/MathEx.cpp: -------------------------------------------------------------------------------- 1 | #include "MathEx.h" 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | MathEx::MathEx() 8 | { 9 | } 10 | 11 | 12 | MathEx::~MathEx() 13 | { 14 | } 15 | 16 | void MathEx::set_eps(int e) 17 | { 18 | EPS = pow(10, -e); 19 | } 20 | 21 | double MathEx::getRound(double d) const 22 | { 23 | double abs_d = abs(d); 24 | int sign = 1; //标记d的正负 25 | if(d<0) 26 | sign = -1; 27 | return static_cast(abs_d/EPS+0.5)*EPS*sign; //四舍五入 28 | } 29 | 30 | double MathEx::op_add(const double &op1, const double &op2) const 31 | { 32 | return op1 + op2; 33 | } 34 | 35 | double MathEx::op_subtract(const double &op1, const double &op2) const 36 | { 37 | return op1 - op2; 38 | } 39 | 40 | double MathEx::op_multiply(const double &op1, const double &op2) const 41 | { 42 | return op1 * op2; 43 | } 44 | 45 | double MathEx::op_divide(const double &op1, const double &op2) const 46 | { 47 | if (abs(op2) < EPS) //除数为0 48 | throw runtime_error(MathExError::DIVISOR_ERROR); 49 | return op1 / op2; 50 | } 51 | 52 | double MathEx::op_mod(const double &op1, const double &op2) const 53 | { 54 | //操作数不是整数 55 | if (abs(op1 - static_cast(op1)) > EPS || abs(op2 - static_cast(op2)) > EPS) 56 | throw runtime_error(MathExError::MOD_ERROR); 57 | //模数为0 58 | if (abs(op2) <= EPS) 59 | throw runtime_error(MathExError::MODULUS_ERROR); 60 | return static_cast(op1) % static_cast(op2); 61 | } 62 | 63 | double MathEx::op_pow(const double &op1, const double &op2) const 64 | { 65 | //操作数不大于0 66 | if (abs(op1) < EPS&&op2 < EPS) 67 | throw runtime_error(MathExError::POW_ERROR); 68 | return pow(op1, op2); 69 | } 70 | 71 | double MathEx::op_square_root(const double &op) const 72 | { 73 | //被开方数为负 74 | if (op < 0) 75 | throw runtime_error(MathExError::RADICAND_ERROR); 76 | return sqrt(op); 77 | } 78 | 79 | double MathEx::op_extract_root(const double &op1, const double &op2) const 80 | { 81 | //被开方数为负 82 | if (op2 < 0) 83 | throw runtime_error(MathExError::RADICAND_ERROR); 84 | return pow(op2, 1 / op1); 85 | } 86 | 87 | double MathEx::op_factorial(const double &op) const 88 | { 89 | int n = static_cast(op), sum = n; 90 | if (op<0 || abs(op - n) > EPS) //阶乘数不为正整数 91 | throw runtime_error(MathExError::FACTORIAL_ERROR); 92 | if (n == 0 || n == 1) 93 | return 1; 94 | while (--n) 95 | sum *= n; 96 | return sum; 97 | } 98 | 99 | double MathEx::op_percent(const double &op) const 100 | { 101 | return op/100; 102 | } 103 | 104 | double MathEx::op_degree_to_radian(const double &op) const 105 | { 106 | return op * PI / 180; 107 | } 108 | 109 | double MathEx::op_sin(const double &op) const 110 | { 111 | return sin(op); 112 | } 113 | 114 | double MathEx::op_cos(const double &op) const 115 | { 116 | return cos(op); 117 | } 118 | 119 | double MathEx::op_tan(const double &op) const 120 | { 121 | double angle = op * 180 / PI; 122 | int i_angle = static_cast(angle); 123 | if (angle - i_angle <= EPS && (i_angle + 90) % 180 == 0) //正切值不为kπ+π/2 124 | throw runtime_error(MathExError::TAN_ERROR); 125 | return tan(op); 126 | } 127 | 128 | double MathEx::op_arcsin(const double &op) const 129 | { 130 | if (abs(op) > 1) //反正弦的定义域为[-1,1] 131 | throw runtime_error(MathExError::ARCSIN_ARCCOS_ERROR); 132 | return asin(op); 133 | } 134 | 135 | double MathEx::op_arccos(const double &op) const 136 | { 137 | if (abs(op) > 1) //反余弦的定义域为[-1,1] 138 | throw runtime_error(MathExError::ARCSIN_ARCCOS_ERROR); 139 | return acos(op); 140 | } 141 | 142 | double MathEx::op_arctan(const double &op) const 143 | { 144 | return atan(op); 145 | } 146 | 147 | double MathEx::op_lg(const double &op) const 148 | { 149 | if (op < EPS) //对数定义域为(0,正无穷) 150 | throw runtime_error(MathExError::ANTILOGARITHM_ERROR); 151 | return log10(op); 152 | } 153 | 154 | double MathEx::op_ln(const double &op) const 155 | { 156 | if (op < EPS) 157 | throw runtime_error(MathExError::ANTILOGARITHM_ERROR); 158 | return log(op); 159 | } 160 | -------------------------------------------------------------------------------- /Calculator/metacharacter.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * metacharacter.h - 运算符定义类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 包含对运算符属性的相关定义 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/10/09 12 | * modification history: 13 | * 1.新增对运算符在图形界面显示的字符的常量定义,便于后期使用 14 | * 2.修改部分运算符的优先级 15 | * 3.添加角度符号相关定义 16 | * 17 | * Copyright:Zix 18 | * Author:Zix 19 | * Date:2016/10/10 20 | * modification history: 21 | * 1.添加独立的百分号和开平方符号定义 22 | * 2.修改部分符号的优先级 23 | * 24 | ******************************************************************************/ 25 | #ifndef METACHARACTER 26 | #define METACHARACTER 27 | #include 28 | #include 29 | 30 | struct Metacharacter { 31 | //0为数字(包括小数点),1为运算符,2为括号 32 | int type; 33 | //栈外优先级,数字为0 34 | int out_priority; 35 | //栈内优先级,数字为0 36 | int in_priority; 37 | //操作数个数,数字和括号为0 38 | int operand; 39 | /*运算符位置,数字和括号为0 40 | *运算符在操作数之前,之间和之后分别为1,2和3表示 41 | */ 42 | int position; 43 | //运算符元素 44 | string e; 45 | }; 46 | 47 | /* 48 | * 各符号的属性表 49 | */ 50 | const map METACHARACTERS{ 51 | /* 52 | * 数字0-9和小数点 53 | */ 54 | { "0", Metacharacter{ 0,0,0,0,0, "0" }}, 55 | { "1", Metacharacter{ 0,0,0,0,0, "1" }}, 56 | { "2", Metacharacter{ 0,0,0,0,0, "2" }}, 57 | { "3", Metacharacter{ 0,0,0,0,0, "3" }}, 58 | { "4", Metacharacter{ 0,0,0,0,0, "4" }}, 59 | { "5", Metacharacter{ 0,0,0,0,0, "5" }}, 60 | { "6", Metacharacter{ 0,0,0,0,0, "6" }}, 61 | { "7", Metacharacter{ 0,0,0,0,0, "7" }}, 62 | { "8", Metacharacter{ 0,0,0,0,0, "8" }}, 63 | { "9", Metacharacter{ 0,0,0,0,0, "9" }}, 64 | { ".", Metacharacter{ 0,0,0,0,0, "." }}, 65 | 66 | /* 67 | * 加减乘除 68 | */ 69 | { "+", Metacharacter{ 1,1,1,2,2, "+" }}, 70 | { "-", Metacharacter{ 1,1,1,2,2, "-" }}, 71 | { "*", Metacharacter{ 1,2,2,2,2, "*" }}, 72 | { "/", Metacharacter{ 1,2,2,2,2, "/" }}, 73 | 74 | { "%", Metacharacter{ 1,2,2,2,2, "%" }}, //求余或百分号 75 | { "^", Metacharacter{ 1,3,3,2,2, "^" }}, //乘方 76 | { "#", Metacharacter{ 1,3,3,2,2, "#" }}, //开多次方 77 | { "<", Metacharacter{ 1,4,4,1,1, "<" }}, //开平方 78 | { "!", Metacharacter{ 1,4,4,1,3, "!" }}, //阶层 79 | 80 | { "sin", Metacharacter{ 1,11,11,1,1, "sin" }}, //正弦(默认弧度) 81 | { "cos", Metacharacter{ 1,11,11,1,1, "cos" }}, //余弦 82 | { "tan", Metacharacter{ 1,11,11,1,1, "tan" }}, //正切 83 | { "arcsin", Metacharacter{ 1,11,11,1,1, "arcsin" }}, //反正弦 84 | { "arccos", Metacharacter{ 1,11,11,1,1, "arccos" }}, //反余弦 85 | { "arctan", Metacharacter{ 1,11,11,1,1, "arctan" }}, //反正切 86 | { "lg", Metacharacter{ 1,11,11,1,1, "lg" }}, //常用对数,以10为底 87 | { "log", Metacharacter{ 1,11,11,1,1, "log" }}, //常用对数,以10为底 88 | { "ln", Metacharacter{ 1,11,11,1,1, "ln" }}, //自然对数,以e为底 89 | 90 | { "`", Metacharacter{ 1,20,20,1,3, "`" }}, //度(角度) 91 | { ">", Metacharacter{ 1,20,20,1,3, ">" }}, //百分号 92 | 93 | /* 94 | * 括号,程序未区分括号形式和优先级,即5*(3+1}是合法的 95 | */ 96 | { "(", Metacharacter{ 2,103,-1,0,0, "(" }}, 97 | { "[", Metacharacter{ 2,102,-1,0,0, "[" }}, 98 | { "{", Metacharacter{ 2,101,-1,0,0, "{" }}, 99 | { ")", Metacharacter{ 2,-1,103,0,0, ")" }}, 100 | { "]", Metacharacter{ 2,-1,102,0,0, "]" }}, 101 | { "}", Metacharacter{ 2,-1,101,0,0, "}" }}, 102 | 103 | { "$", Metacharacter{ 3,-10,-10,0,0, "$" }}, //结束符号 104 | }; 105 | 106 | /* 107 | * 用于在图形化界面显示的字符 108 | */ 109 | const string ZERO = "0"; 110 | const string ONE = "1"; 111 | const string TWO = "2"; 112 | const string THREE = "3"; 113 | const string FOUR = "4"; 114 | const string FIVE = "5"; 115 | const string SIX = "6"; 116 | const string SEVEN = "7"; 117 | const string EIGHT = "8"; 118 | const string NINE = "9"; 119 | const string POINT = "."; 120 | const string ADD = "+"; 121 | const string MINUS = "-"; 122 | const string MULTIPLY = "×"; 123 | const string DIVIDE = "÷"; 124 | const string EQUAL = "="; 125 | const string DEGREE = "°"; 126 | const string MOD_PERCENT = "%"; 127 | const string POW = "^"; 128 | const string EXTRACT_ROOT = "√"; 129 | const string FACTORIAL = "!"; 130 | const string SIN = "sin"; 131 | const string COS = "cos"; 132 | const string TAN = "tan"; 133 | const string ARCSIN = "arcsin"; 134 | const string ARCCOS = "arccos"; 135 | const string ARCTAN = "arctan"; 136 | const string LG = "lg"; 137 | const string LOG = "log"; 138 | const string LN = "ln"; 139 | const string LEFT_BRACKET = "("; 140 | const string RIGHT_BRACKET = ")"; 141 | 142 | #endif // METACHARACTER 143 | 144 | -------------------------------------------------------------------------------- /math_expr_eval/metacharacter.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * metacharacter.h - 运算符定义类 3 | * 4 | * Copyright (c) 20015-2016 Zix 5 | * 6 | * DESCRIPTION: - 7 | * 包含对运算符属性的相关定义 8 | * 9 | * Copyright:Zix 10 | * Author:Zix 11 | * Date:2016/10/09 12 | * modification history: 13 | * 1.新增对运算符在图形界面显示的字符的常量定义,便于后期使用 14 | * 2.修改部分运算符的优先级 15 | * 3.添加角度符号相关定义 16 | * 17 | * Copyright:Zix 18 | * Author:Zix 19 | * Date:2016/10/10 20 | * modification history: 21 | * 1.添加独立的百分号和开平方符号定义 22 | * 2.修改部分符号的优先级 23 | * 24 | ******************************************************************************/ 25 | #ifndef METACHARACTER 26 | #define METACHARACTER 27 | #include 28 | #include 29 | 30 | struct Metacharacter { 31 | //0为数字(包括小数点),1为运算符,2为括号 32 | int type; 33 | //栈外优先级,数字为0 34 | int out_priority; 35 | //栈内优先级,数字为0 36 | int in_priority; 37 | //操作数个数,数字和括号为0 38 | int operand; 39 | /*运算符位置,数字和括号为0 40 | *运算符在操作数之前,之间和之后分别为1,2和3表示 41 | */ 42 | int position; 43 | //运算符元素 44 | string e; 45 | }; 46 | 47 | /* 48 | * 各符号的属性表 49 | */ 50 | const map METACHARACTERS{ 51 | /* 52 | * 数字0-9和小数点 53 | */ 54 | { "0", Metacharacter{ 0,0,0,0,0, "0" }}, 55 | { "1", Metacharacter{ 0,0,0,0,0, "1" }}, 56 | { "2", Metacharacter{ 0,0,0,0,0, "2" }}, 57 | { "3", Metacharacter{ 0,0,0,0,0, "3" }}, 58 | { "4", Metacharacter{ 0,0,0,0,0, "4" }}, 59 | { "5", Metacharacter{ 0,0,0,0,0, "5" }}, 60 | { "6", Metacharacter{ 0,0,0,0,0, "6" }}, 61 | { "7", Metacharacter{ 0,0,0,0,0, "7" }}, 62 | { "8", Metacharacter{ 0,0,0,0,0, "8" }}, 63 | { "9", Metacharacter{ 0,0,0,0,0, "9" }}, 64 | { ".", Metacharacter{ 0,0,0,0,0, "." }}, 65 | 66 | /* 67 | * 加减乘除 68 | */ 69 | { "+", Metacharacter{ 1,1,1,2,2, "+" }}, 70 | { "-", Metacharacter{ 1,1,1,2,2, "-" }}, 71 | { "*", Metacharacter{ 1,2,2,2,2, "*" }}, 72 | { "/", Metacharacter{ 1,2,2,2,2, "/" }}, 73 | 74 | { "%", Metacharacter{ 1,2,2,2,2, "%" }}, //求余或百分号 75 | { "^", Metacharacter{ 1,3,3,2,2, "^" }}, //乘方 76 | { "#", Metacharacter{ 1,3,3,2,2, "#" }}, //开多次方 77 | { "<", Metacharacter{ 1,4,4,1,1, "<" }}, //开平方 78 | { "!", Metacharacter{ 1,4,4,1,3, "!" }}, //阶层 79 | 80 | { "sin", Metacharacter{ 1,11,11,1,1, "sin" }}, //正弦(默认弧度) 81 | { "cos", Metacharacter{ 1,11,11,1,1, "cos" }}, //余弦 82 | { "tan", Metacharacter{ 1,11,11,1,1, "tan" }}, //正切 83 | { "arcsin", Metacharacter{ 1,11,11,1,1, "arcsin" }}, //反正弦 84 | { "arccos", Metacharacter{ 1,11,11,1,1, "arccos" }}, //反余弦 85 | { "arctan", Metacharacter{ 1,11,11,1,1, "arctan" }}, //反正切 86 | { "lg", Metacharacter{ 1,11,11,1,1, "lg" }}, //常用对数,以10为底 87 | { "log", Metacharacter{ 1,11,11,1,1, "log" }}, //常用对数,以10为底 88 | { "ln", Metacharacter{ 1,11,11,1,1, "ln" }}, //自然对数,以e为底 89 | 90 | { "`", Metacharacter{ 1,20,20,1,3, "`" }}, //度(角度) 91 | { ">", Metacharacter{ 1,20,20,1,3, ">" }}, //百分号 92 | 93 | /* 94 | * 括号,程序未区分括号形式和优先级,即5*(3+1}是合法的 95 | */ 96 | { "(", Metacharacter{ 2,103,-1,0,0, "(" }}, 97 | { "[", Metacharacter{ 2,102,-1,0,0, "[" }}, 98 | { "{", Metacharacter{ 2,101,-1,0,0, "{" }}, 99 | { ")", Metacharacter{ 2,-1,103,0,0, ")" }}, 100 | { "]", Metacharacter{ 2,-1,102,0,0, "]" }}, 101 | { "}", Metacharacter{ 2,-1,101,0,0, "}" }}, 102 | 103 | { "$", Metacharacter{ 3,-10,-10,0,0, "$" }}, //结束符号 104 | }; 105 | 106 | /* 107 | * 用于在图形化界面显示的字符 108 | */ 109 | const string ZERO = "0"; 110 | const string ONE = "1"; 111 | const string TWO = "2"; 112 | const string THREE = "3"; 113 | const string FOUR = "4"; 114 | const string FIVE = "5"; 115 | const string SIX = "6"; 116 | const string SEVEN = "7"; 117 | const string EIGHT = "8"; 118 | const string NINE = "9"; 119 | const string POINT = "."; 120 | const string ADD = "+"; 121 | const string MINUS = "-"; 122 | const string MULTIPLY = "×"; 123 | const string DIVIDE = "÷"; 124 | const string EQUAL = "="; 125 | const string DEGREE = "°"; 126 | const string MOD_PERCENT = "%"; 127 | const string POW = "^"; 128 | const string EXTRACT_ROOT = "√"; 129 | const string FACTORIAL = "!"; 130 | const string SIN = "sin"; 131 | const string COS = "cos"; 132 | const string TAN = "tan"; 133 | const string ARCSIN = "arcsin"; 134 | const string ARCCOS = "arccos"; 135 | const string ARCTAN = "arctan"; 136 | const string LG = "lg"; 137 | const string LOG = "log"; 138 | const string LN = "ln"; 139 | const string LEFT_BRACKET = "("; 140 | const string RIGHT_BRACKET = ")"; 141 | 142 | #endif // METACHARACTER 143 | 144 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | 238 | 239 | # C++ objects and libs 240 | 241 | *.slo 242 | *.lo 243 | *.o 244 | *.a 245 | *.la 246 | *.lai 247 | *.so 248 | *.dll 249 | *.dylib 250 | 251 | # Qt-es 252 | 253 | /.qmake.cache 254 | /.qmake.stash 255 | *.pro.user 256 | *.pro.user.* 257 | *.qbs.user 258 | *.qbs.user.* 259 | *.moc 260 | moc_*.cpp 261 | qrc_*.cpp 262 | ui_*.h 263 | Makefile* 264 | *build-* 265 | 266 | # QtCreator 267 | 268 | *.autosave 269 | 270 | # QtCtreator Qml 271 | *.qmlproject.user 272 | *.qmlproject.user.* 273 | 274 | # QtCtreator CMake 275 | CMakeLists.txt.user 276 | -------------------------------------------------------------------------------- /Calculator/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | 5 | MainWindow::MainWindow(QWidget *parent) 6 | : QMainWindow(parent) 7 | { 8 | //setWindowFlags(Qt::CustomizeWindowHint); 9 | menuBar()->close(); 10 | 11 | setStyleSheet("QPushButton{" 12 | "background-color:gray;" 13 | "color: white;" 14 | "width:55px;" 15 | "height:55px;" 16 | "font-size: 15px;" 17 | "border-radius: 10px;" 18 | "border: 2px groove gray;" 19 | "border-style: outset;}" 20 | 21 | "QPushButton:hover{" 22 | "background-color:white;" 23 | "color: black;}" 24 | 25 | "QPushButton:pressed,QPushButton:disabled{" 26 | "color: white;" 27 | "background-color:rgb(0, 0, 0);" 28 | "border-style: inset; }"); 29 | 30 | CentralWidget=new QWidget(this); 31 | setCentralWidget(CentralWidget); 32 | setWindowTitle(tr("Calculator")); 33 | buttonsLayout = new QGridLayout(); 34 | /* 35 | * 根据BUTTONS表添加,设置按钮 36 | */ 37 | for(int i=0; i row = BUTTONS.at(i); //一行按钮 40 | for(int j=0; jaddWidget(pushButton, i, j); 49 | } 50 | } 51 | } 52 | 53 | /* 54 | * 功能键 55 | */ 56 | functionKeyButtonClear=new QPushButton(QString::fromStdString(CLEAR)); 57 | functionKeyButtonBackspace=new QPushButton(QString::fromStdString(BACKSPACE)); 58 | functionKeyButtonAns=new QPushButton(QString::fromStdString(ANS)); 59 | functionKeyButtonShift=new QPushButton(QString::fromStdString(SHIFT)); 60 | equalButton = new QPushButton(QString::fromStdString(EQUAL)); 61 | 62 | connect(functionKeyButtonBackspace,&QPushButton::clicked,this,&MainWindow::onBackspaceClicked); 63 | connect(functionKeyButtonClear,&QPushButton::clicked,this,&MainWindow::onClearClicked); 64 | connect(functionKeyButtonAns,&QPushButton::clicked,this,&MainWindow::onAnsClicked); 65 | connect(functionKeyButtonShift,&QPushButton::clicked,this,&MainWindow::onShiftClicked); 66 | connect(equalButton, &QPushButton::clicked, this, &MainWindow::onEqualClicked); 67 | 68 | buttonsLayout->addWidget(functionKeyButtonBackspace, 1, 0); 69 | buttonsLayout->addWidget(functionKeyButtonClear, 1, 1); 70 | buttonsLayout->addWidget(functionKeyButtonAns, 1, 2); 71 | buttonsLayout->addWidget(functionKeyButtonShift, 0, 4); 72 | //将等号添加至最后一行最后两格位置 73 | buttonsLayout->addWidget(equalButton, BUTTONS.size(), BUTTONS.at(BUTTONS.size()-1).size()-2, 1, 2); 74 | 75 | 76 | MainLayout=new QGridLayout(CentralWidget); 77 | //设置表达式输入框 78 | inputText=new QLineEdit("0"); 79 | inputText->setAlignment(Qt::AlignRight); 80 | inputText->setReadOnly(true); 81 | inputText->setStyleSheet("QLineEdit{height: 50px;" 82 | "border-style: plain;" 83 | "border-radius: 10px;" 84 | "font-size: 30px}"); 85 | //设置等于符号 86 | equalLabel = new QLabel("="); 87 | equalLabel->setStyleSheet("width:55px;" 88 | "height:55px;" 89 | "font-size: 30px;"); 90 | //设置结果显示框 91 | resultText = new QLineEdit("0"); 92 | resultText->setReadOnly(true); 93 | resultText->setStyleSheet("QLineEdit{height: 50px;" 94 | "border-style: plain;" 95 | "border-radius: 10px;" 96 | "font-size: 30px}"); 97 | MainLayout->addWidget(inputText, 0, 0, 1, 5); 98 | MainLayout->addWidget(equalLabel, 1, 1); 99 | MainLayout->addWidget(resultText, 1, 2, 1, 3); 100 | MainLayout->addLayout(buttonsLayout, 2, 0, 7, 5); 101 | MainLayout->setSizeConstraint(QLayout::SetFixedSize); 102 | setFixedSize(MainLayout->sizeHint()); 103 | } 104 | 105 | MainWindow::~MainWindow() 106 | { 107 | 108 | } 109 | 110 | QString MainWindow::cal(QString s) 111 | { 112 | QString temp; 113 | expression = new Expression(transformStdExpression(s)); 114 | try 115 | { 116 | temp=QString::fromStdString(expression->getResult()); 117 | }catch(runtime_error e){ 118 | QMessageBox messagebox(QMessageBox::Warning,"错误",QString::fromStdString(e.what())); 119 | messagebox.exec(); 120 | temp = "Error"; 121 | } 122 | 123 | calcFinished = true; 124 | delete expression; 125 | return temp; 126 | } 127 | 128 | string MainWindow::transformStdExpression(QString expression) 129 | { 130 | expression = expression.replace("×", "*").replace("÷", "/").replace("√", "#").replace("°", "`"); 131 | return expression.toStdString(); 132 | } 133 | 134 | void MainWindow::setInputText(PushButton *pushButton) 135 | { 136 | QString symbol = pushButton->text(); 137 | /* 138 | * 未计算完成,还在输入中,将输入的字符直接添加至表达式输入框文本后 139 | */ 140 | if(calcFinished==false) 141 | { 142 | inputText->setText(inputText->text()+pushButton->text()); 143 | } 144 | /* 145 | * 已经计算完成,准备开始下一次计算 146 | * 根据输入的内容,若为数字/括号/前置运算符/可省略第一个操作数的中置运算符,则直接将输入显示在输入框中 147 | */ 148 | else 149 | { 150 | Metacharacter m = METACHARACTERS.at(transformStdExpression(symbol)); 151 | if(m.type == 0 || m.type == 2 || (m.type==1 && (m.position == 1 || m.e == "#" || m.e == "-"))) 152 | { 153 | //如果输入的是小数点,则在其前面添加小数点 154 | if(symbol == ".") 155 | { 156 | inputText->setText(QString("0.")); 157 | } 158 | else 159 | { 160 | inputText->setText(pushButton->text()); 161 | } 162 | } 163 | else if(m.type == 1) 164 | { 165 | inputText->setText(Ans + pushButton->text()); 166 | } 167 | historySize.clear(); //清空上次输入的历史记录 168 | calcFinished=false; //表示正在输入过程中 169 | } 170 | historySize.push(pushButton->text().size()); //记录输入的操作词大小 171 | } 172 | 173 | void MainWindow::onEqualClicked() 174 | { 175 | QString temp; 176 | temp=cal(inputText->text()); 177 | if(temp=="Error") //如果计算出错 178 | { 179 | resultText->setText(tr("Error")); 180 | Ans = "0"; 181 | return; 182 | } 183 | 184 | /* 185 | * 由于返回值为double转换的QString,字符串小数位会有一串0,需要去除,并在小数位全为0时去除小数点 186 | */ 187 | while(temp.right(1)=="0") 188 | temp=temp.left(temp.size()-1); 189 | if(temp.right(1)==".") 190 | temp=temp.left(temp.size()-1); 191 | resultText->setText(temp); 192 | /* 193 | * 如果计算结果为负数,为Ans加上括号便于下次计算使用 194 | */ 195 | if(temp.at(0) == '-') 196 | Ans=QString("%1%2%3").arg("(").arg(temp).arg(")"); 197 | else 198 | Ans = temp; 199 | } 200 | 201 | void MainWindow::onClearClicked() 202 | { 203 | inputText->setText("0"); 204 | historySize.clear(); 205 | calcFinished=true; 206 | } 207 | 208 | void MainWindow::onAnsClicked() 209 | { 210 | if(inputText->text()=="0"||calcFinished==true) 211 | { 212 | inputText->setText(Ans); 213 | calcFinished=false; 214 | } 215 | else 216 | inputText->setText(inputText->text()+Ans); 217 | int length = Ans.size(); 218 | while(length--) 219 | historySize.push(1); 220 | } 221 | 222 | void MainWindow::onShiftClicked() 223 | { 224 | /* 225 | * 根据shift按下状态转换sin,cos,tan和lg四个按钮 226 | */ 227 | if(isShifting) 228 | { 229 | isShifting = false; 230 | for(int i=0; i<4; ++i) 231 | { 232 | buttons[i]->setText(QString::fromStdString(BUTTONS.at(0).at(i))); 233 | } 234 | functionKeyButtonShift->setStyleSheet("QPushButton{background-color:gray;" 235 | "font-size: 15px;" 236 | "border-style: outset;}" 237 | "QPushButton:hover{" 238 | "background-color:white;" 239 | "color: black;}" 240 | "QPushButton:pressed{" 241 | "background-color:rgb(0, 0, 0);" 242 | "border-style: inset;}"); 243 | } 244 | else 245 | { 246 | isShifting = true; 247 | for(int i=0; i<4; ++i) 248 | { 249 | buttons[i]->setText(QString::fromStdString(SHIFT_TABLE[buttons[i]->text().toStdString()])); 250 | } 251 | functionKeyButtonShift->setStyleSheet("QPushButton:pressed{background-color:gray;" 252 | "border-style: outset;}" 253 | "QPushButton:hover{" 254 | "background-color:white;" 255 | "color: black;}" 256 | "QPushButton{" 257 | "font-size: 40px;" 258 | "font-style: bold;" 259 | "background-color:rgb(0, 0, 0);" 260 | "border-style: inset;}"); 261 | } 262 | } 263 | 264 | void MainWindow::onBackspaceClicked() 265 | { 266 | QString result=inputText->text(); 267 | calcFinished = false; //计算完成时若按下删除键,重新将计算完成标记置为正在输入中 268 | if(result.size()==1) //输入框只剩一个字符 269 | { 270 | historySize.clear(); 271 | inputText->setText("0"); 272 | calcFinished = true; 273 | } 274 | else 275 | { 276 | int length = historySize.empty() ? 1:historySize.pop(); //兼容手动输入字符情况 277 | inputText->setText(result.left(result.size()-length)); 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Calculator/Expression.cpp: -------------------------------------------------------------------------------- 1 | #include "Expression.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | 11 | Expression::Expression(string str, int precision) 12 | { 13 | raw_exp = str; 14 | mathEx.set_eps(precision); 15 | } 16 | 17 | Expression::~Expression() 18 | { 19 | } 20 | 21 | /* 22 | * 对表达式进行初步合法性检查,包括字符以及字符组成的运算单元是否合法 23 | */ 24 | bool Expression::simpleCheck() 25 | { 26 | string temp; 27 | bool getWord = false; //获取操作符中 28 | int isAlpha = 0; //当前字符是否为字母 29 | for (auto &i : raw_exp) 30 | { 31 | isAlpha = isalpha(i); //判断当前字符是否为字母 32 | if (getWord) 33 | { 34 | /* 35 | * 处于操作词构成过程中,继续添加字母 36 | */ 37 | if (isAlpha) 38 | { 39 | temp += i; 40 | continue; //跳过后续 41 | } 42 | } 43 | else 44 | { 45 | /* 46 | * 读取到一个字母,开启操作词构成过程 47 | */ 48 | if (isAlpha) 49 | { 50 | getWord = true; 51 | temp += i; 52 | continue; //跳过后续 53 | } 54 | else 55 | temp += i; //读取到非字母,操作词构成过程结束 56 | } 57 | 58 | /* 59 | * 如果读取到的操作词不在元字符表中或为结束符,抛出异常 60 | */ 61 | if (METACHARACTERS.find(temp) == METACHARACTERS.end() || temp == "$") 62 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + temp); 63 | 64 | /* 65 | * 重置操作词构成过程标识 66 | */ 67 | if (getWord) 68 | { 69 | getWord = false; 70 | } 71 | temp = ""; //清空 72 | } 73 | 74 | if (getWord) 75 | throw runtime_error(ExpressionError::ILLEGAL_BRACKET_ERROR); 76 | return true; 77 | } 78 | 79 | /* 80 | * 词法分析,构字成词 81 | */ 82 | bool Expression::split() 83 | { 84 | string::size_type i = 0; 85 | string::size_type temp = 0; 86 | while (i= raw_exp.size()) 99 | break; 100 | } while (isdigit(raw_exp[i]) || ((!getPoint) && raw_exp[i] == '.')); 101 | exp.push_back(Metacharacter{ 0,0,0,0,0, raw_exp.substr(temp, i - temp) }); 102 | } 103 | else if (raw_exp[i] == '.') //读取到不在数字之后的小数点,抛出异常 104 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + "."); 105 | else if (METACHARACTERS.find(str_temp)!=METACHARACTERS.end()) //读取到操作符 106 | { 107 | exp.push_back(METACHARACTERS.at(str_temp)); 108 | ++i; 109 | } 110 | else if (isalpha(raw_exp[i])) //读取到操作词 111 | { 112 | temp = i; 113 | do 114 | { 115 | if (++i >= raw_exp.size()) 116 | break; 117 | } while (isalpha(raw_exp[i])); 118 | str_temp = raw_exp.substr(temp, i - temp); 119 | exp.push_back(METACHARACTERS.at(str_temp)); 120 | } 121 | } 122 | return true; 123 | } 124 | 125 | /* 126 | * 负号处理 127 | */ 128 | void Expression::negativeOperatorPreprocessing() 129 | { 130 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 131 | { 132 | if ((*i).e == "-") 133 | { 134 | //如果负号在表达式首位,在负号前添加数字0 135 | if (i == exp.begin()) 136 | { 137 | i = exp.insert(i, METACHARACTERS.at("0")); 138 | } 139 | else 140 | { 141 | //如果负号前为括号,在负号前添加数字0 142 | --i; 143 | if ((*i).out_priority >= 100) 144 | { 145 | ++i; 146 | i = exp.insert(i, METACHARACTERS.at("0")); 147 | } 148 | ++i; 149 | } 150 | } 151 | } 152 | } 153 | 154 | //查找开平方运算并替换为开平方运算符 155 | void Expression::sqrtOperatorPreprocessing() 156 | { 157 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 158 | { 159 | if ((*i).e == "#") 160 | { 161 | //如果根号在表达式第一个位置 162 | if (i == exp.begin()) 163 | { 164 | *i = METACHARACTERS.at("<"); 165 | } 166 | else 167 | { 168 | --i; 169 | //如果根号前为左括号,前置运算符或中置运算符,为开平方 170 | if ((*i).out_priority >= 100 || (*i).position == 1 || (*i).position == 2) 171 | { 172 | if(i->type == 1 && i->in_priority >= METACHARACTERS.at("<").in_priority) 173 | throw runtime_error(ExpressionError::SQUARE_ROOT_ERROR); 174 | ++i; 175 | *i = METACHARACTERS.at("<"); 176 | } 177 | else 178 | ++i; 179 | } 180 | } 181 | } 182 | } 183 | 184 | //根据下文对%进行判断,如果下文为表达式尾或中置和后置运算符,则%为百分号操作,否则为模操作 185 | void Expression::percentOperatorPreprocessing() 186 | { 187 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 188 | { 189 | if ((*i).e == "%") 190 | { 191 | ++i; 192 | /* 193 | * 如果%后为表达式尾,中置或后置运算符,则%为百分号运算,为避免二义性,将其替换为百分号运算 194 | */ 195 | if (i == exp.end() || (*i).position == 2 || (*i).position == 3) 196 | { 197 | /* 198 | * 百分号前只能为数字或括号包围的表达式 199 | */ 200 | --i;--i; 201 | if(i->type!=0 && i->in_priority<=100) 202 | throw runtime_error(ExpressionError::PERCENT_OPERATOR_ERROR); 203 | ++i; 204 | *i = METACHARACTERS.at(">"); 205 | } 206 | } 207 | } 208 | } 209 | 210 | /** 211 | * 为了保证°的优先计算,对其及前面的数字加上括号 212 | */ 213 | void Expression::degreeOperatorPreprocessing() 214 | { 215 | //与对百分号处理类似,只是无需对后一个操作词进行判断,°无二义性 216 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 217 | { 218 | if ((*i).e == "`") 219 | { 220 | /* 221 | * 角度前只能为数字或括号包围的表达式 222 | */ 223 | --i; 224 | if(i->type!=0 && i->in_priority<=100) 225 | throw runtime_error(ExpressionError::DEGREE_OPERATOR_ERROR); 226 | ++i; 227 | } 228 | } 229 | } 230 | 231 | //将大/中操作转换为对应的小括号 232 | void Expression::bracketPreprocessing() 233 | { 234 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 235 | { 236 | //转换左括号 237 | if ((*i).out_priority ==101 || (*i).out_priority == 102) 238 | { 239 | i = exp.erase(i); 240 | i = exp.insert(i, METACHARACTERS.at("(")); 241 | } 242 | //转换右括号 243 | else if ((*i).in_priority == 101 || (*i).in_priority == 102) 244 | { 245 | i = exp.erase(i); 246 | i = exp.insert(i, METACHARACTERS.at(")")); 247 | } 248 | } 249 | } 250 | 251 | //对分割后的表达式进行预处理,便于接下来的操作 252 | void Expression::preprocessing() 253 | { 254 | negativeOperatorPreprocessing(); 255 | sqrtOperatorPreprocessing(); 256 | percentOperatorPreprocessing(); 257 | bracketPreprocessing(); 258 | degreeOperatorPreprocessing(); 259 | } 260 | 261 | void Expression::operation() 262 | { 263 | if (op.top().operand == 1) //若为一元运算符 264 | { 265 | double op1; if (op.empty()) 266 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 267 | else 268 | calc(op.top(), op1); 269 | } 270 | else //若为二元运算符 271 | { 272 | double op1, op2; 273 | if (op.empty()) 274 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 275 | else 276 | calc(op.top(), op1, op2); 277 | } 278 | op.pop(); 279 | } 280 | 281 | 282 | void Expression::transToPostfix() 283 | { 284 | try { 285 | exp.push_front(METACHARACTERS.at("$")); 286 | for (auto i : exp) 287 | { 288 | //如果当前元素为操作数,压入操作数栈 289 | if (i.type == 0) 290 | number.push(stod(i.e)); 291 | //如果当前元素为运算符,比较其与运算符栈顶元素的优先级 292 | else if (i.type == 1) 293 | { 294 | /* 295 | * 如果小于栈顶运算符优先级, 296 | * 不断出栈栈顶运算符直到栈顶运算符优先级小于当前运算符优先级, 297 | * 并依次对出栈的运算符进行运算 298 | * 然后入栈当前运算符 299 | */ 300 | if (i.out_priority <= op.top().in_priority) 301 | { 302 | do 303 | { 304 | operation(); 305 | } while (i.out_priority <= op.top().in_priority); 306 | } 307 | op.push(i); 308 | } 309 | //如果当前运算符为括号 310 | else if (i.type == 2) 311 | { 312 | //如果当前括号为左括号,入栈 313 | if (i.out_priority > 0) 314 | { 315 | op.push(i); 316 | //lastBracket = i; 317 | } 318 | //如果当前括号为右括号,出栈运算符栈直到遇到第一个左括号 319 | else if (i.out_priority < 0) 320 | { 321 | // //一对括号内无内容,抛出括号异常 322 | // if (op.top().out_priority>100) 323 | // throw runtime_error(ExpressionError::NEEDLESS_BARCKET_ERROR); 324 | 325 | while (op.top().type != 2) 326 | { 327 | operation(); 328 | } 329 | 330 | op.pop(); 331 | if (op.empty()) 332 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 333 | } 334 | } 335 | //表达式边缘标识符$直接压入运算符栈 336 | else if (i.type == 3) 337 | op.push(i); 338 | } 339 | 340 | //对运算符栈剩余的运算符依次出栈并进行运算 341 | while (op.size() > 1) 342 | { 343 | operation(); 344 | } 345 | 346 | if(number.size() > 1) 347 | { 348 | throw runtime_error(ExpressionError::MISSING_OPERATOR_ERROR); 349 | } 350 | } 351 | catch (...) { 352 | throw; 353 | } 354 | } 355 | 356 | //单目运算符运算 357 | void Expression::calc(Metacharacter mc, double & op1) 358 | { 359 | if (number.empty()) 360 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 361 | else 362 | { 363 | op1 = number.top(); 364 | number.pop(); 365 | } 366 | try { 367 | if (mc.e == "!") 368 | number.push(mathEx.op_factorial(op1)); 369 | else if (mc.e == "`") 370 | number.push(mathEx.op_degree_to_radian(op1)); 371 | else if (mc.e == ">") 372 | number.push(mathEx.op_percent(op1)); 373 | else if (mc.e == "<") 374 | number.push(mathEx.op_square_root(op1)); 375 | else if (mc.e == "sin") 376 | number.push(mathEx.op_sin(op1)); 377 | else if (mc.e == "cos") 378 | number.push(mathEx.op_cos(op1)); 379 | else if (mc.e == "tan") 380 | number.push(mathEx.op_tan(op1)); 381 | else if (mc.e == "arcsin") 382 | number.push(mathEx.op_arcsin(op1)); 383 | else if (mc.e == "arccos") 384 | number.push(mathEx.op_arccos(op1)); 385 | else if (mc.e == "arctan") 386 | number.push(mathEx.op_arctan(op1)); 387 | else if (mc.e == "log" || mc.e == "lg") 388 | number.push(mathEx.op_lg(op1)); 389 | else if (mc.e == "ln") 390 | number.push(mathEx.op_ln(op1)); 391 | else 392 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + mc.e); 393 | } 394 | catch (runtime_error) { 395 | throw; 396 | } 397 | 398 | } 399 | 400 | //双目运算符运算 401 | void Expression::calc(Metacharacter mc, double & op1, double & op2) 402 | { 403 | if (number.empty()) //数字栈为空,缺少操作数2 404 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 405 | else 406 | { 407 | op2 = number.top(); 408 | number.pop(); 409 | } 410 | if (number.empty()) //数字栈为空,缺少操作数1 411 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 412 | else 413 | { 414 | op1 = number.top(); 415 | number.pop(); 416 | } 417 | try { 418 | if (mc.e == "+") 419 | number.push(mathEx.op_add(op1, op2)); 420 | else if (mc.e == "-") 421 | number.push(mathEx.op_subtract(op1, op2)); 422 | else if (mc.e == "*") 423 | number.push(mathEx.op_multiply(op1, op2)); 424 | else if (mc.e == "/") 425 | number.push(mathEx.op_divide(op1, op2)); 426 | else if (mc.e == "^") 427 | number.push(mathEx.op_pow(op1, op2)); 428 | else if (mc.e == "%") 429 | number.push(mathEx.op_mod(op1, op2)); 430 | else if (mc.e == "#") 431 | number.push(mathEx.op_extract_root(op1, op2)); 432 | else 433 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + mc.e); 434 | } 435 | catch (runtime_error) { 436 | throw; 437 | } 438 | } 439 | 440 | /* 441 | * 计算 442 | */ 443 | string Expression::getResult() 444 | { 445 | try { 446 | simpleCheck(); //字符合法性检查 447 | split(); //构字成词 448 | preprocessing(); //特殊运算符预处理 449 | transToPostfix(); //转换为逆波兰式并计算 450 | // for (auto &i : exp) 451 | // { 452 | // cout << i.e << ' '; 453 | // } 454 | } catch (runtime_error &){ 455 | throw; 456 | } 457 | result = number.top(); //数字栈中最后一个数即为结果 458 | return to_string(mathEx.getRound(result)); 459 | } 460 | 461 | 462 | -------------------------------------------------------------------------------- /math_expr_eval/Expression.cpp: -------------------------------------------------------------------------------- 1 | #include "Expression.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | 11 | Expression::Expression(string str, int precision) 12 | { 13 | raw_exp = str; 14 | mathEx.set_eps(precision); 15 | } 16 | 17 | Expression::~Expression() 18 | { 19 | } 20 | 21 | /* 22 | * 对表达式进行初步合法性检查,包括字符以及字符组成的运算单元是否合法 23 | */ 24 | bool Expression::simpleCheck() 25 | { 26 | string temp; 27 | bool getWord = false; //获取操作符中 28 | int isAlpha = 0; //当前字符是否为字母 29 | for (auto &i : raw_exp) 30 | { 31 | isAlpha = isalpha(i); //判断当前字符是否为字母 32 | if (getWord) 33 | { 34 | /* 35 | * 处于操作词构成过程中,继续添加字母 36 | */ 37 | if (isAlpha) 38 | { 39 | temp += i; 40 | continue; //跳过后续 41 | } 42 | } 43 | else 44 | { 45 | /* 46 | * 读取到一个字母,开启操作词构成过程 47 | */ 48 | if (isAlpha) 49 | { 50 | getWord = true; 51 | temp += i; 52 | continue; //跳过后续 53 | } 54 | else 55 | temp += i; //读取到非字母,操作词构成过程结束 56 | } 57 | 58 | /* 59 | * 如果读取到的操作词不在元字符表中或为结束符,抛出异常 60 | */ 61 | if (METACHARACTERS.find(temp) == METACHARACTERS.end() || temp == "$") 62 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + temp); 63 | 64 | /* 65 | * 重置操作词构成过程标识 66 | */ 67 | if (getWord) 68 | { 69 | getWord = false; 70 | } 71 | temp = ""; //清空 72 | } 73 | 74 | if (getWord) 75 | throw runtime_error(ExpressionError::ILLEGAL_BRACKET_ERROR); 76 | return true; 77 | } 78 | 79 | /* 80 | * 词法分析,构字成词 81 | */ 82 | bool Expression::split() 83 | { 84 | string::size_type i = 0; 85 | string::size_type temp = 0; 86 | while (i= raw_exp.size()) 99 | break; 100 | } while (isdigit(raw_exp[i]) || ((!getPoint) && raw_exp[i] == '.')); 101 | exp.push_back(Metacharacter{ 0,0,0,0,0, raw_exp.substr(temp, i - temp) }); 102 | } 103 | else if (raw_exp[i] == '.') //读取到不在数字之后的小数点,抛出异常 104 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + "."); 105 | else if (METACHARACTERS.find(str_temp)!=METACHARACTERS.end()) //读取到操作符 106 | { 107 | exp.push_back(METACHARACTERS.at(str_temp)); 108 | ++i; 109 | } 110 | else if (isalpha(raw_exp[i])) //读取到操作词 111 | { 112 | temp = i; 113 | do 114 | { 115 | if (++i >= raw_exp.size()) 116 | break; 117 | } while (isalpha(raw_exp[i])); 118 | str_temp = raw_exp.substr(temp, i - temp); 119 | exp.push_back(METACHARACTERS.at(str_temp)); 120 | } 121 | } 122 | return true; 123 | } 124 | 125 | /* 126 | * 负号处理 127 | */ 128 | void Expression::negativeOperatorPreprocessing() 129 | { 130 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 131 | { 132 | if ((*i).e == "-") 133 | { 134 | //如果负号在表达式首位,在负号前添加数字0 135 | if (i == exp.begin()) 136 | { 137 | i = exp.insert(i, METACHARACTERS.at("0")); 138 | } 139 | else 140 | { 141 | //如果负号前为括号,在负号前添加数字0 142 | --i; 143 | if ((*i).out_priority >= 100) 144 | { 145 | ++i; 146 | i = exp.insert(i, METACHARACTERS.at("0")); 147 | } 148 | ++i; 149 | } 150 | } 151 | } 152 | } 153 | 154 | //查找开平方运算并替换为开平方运算符 155 | void Expression::sqrtOperatorPreprocessing() 156 | { 157 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 158 | { 159 | if ((*i).e == "#") 160 | { 161 | //如果根号在表达式第一个位置 162 | if (i == exp.begin()) 163 | { 164 | *i = METACHARACTERS.at("<"); 165 | } 166 | else 167 | { 168 | --i; 169 | //如果根号前为左括号,前置运算符或中置运算符,为开平方 170 | if ((*i).out_priority >= 100 || (*i).position == 1 || (*i).position == 2) 171 | { 172 | if(i->type == 1 && i->in_priority >= METACHARACTERS.at("<").in_priority) 173 | throw runtime_error(ExpressionError::SQUARE_ROOT_ERROR); 174 | ++i; 175 | *i = METACHARACTERS.at("<"); 176 | } 177 | else 178 | ++i; 179 | } 180 | } 181 | } 182 | } 183 | 184 | //根据下文对%进行判断,如果下文为表达式尾或中置和后置运算符,则%为百分号操作,否则为模操作 185 | void Expression::percentOperatorPreprocessing() 186 | { 187 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 188 | { 189 | if ((*i).e == "%") 190 | { 191 | ++i; 192 | /* 193 | * 如果%后为表达式尾,中置或后置运算符,则%为百分号运算,为避免二义性,将其替换为百分号运算 194 | */ 195 | if (i == exp.end() || (*i).position == 2 || (*i).position == 3) 196 | { 197 | /* 198 | * 百分号前只能为数字或括号包围的表达式 199 | */ 200 | --i;--i; 201 | if(i->type!=0 && i->in_priority<=100) 202 | throw runtime_error(ExpressionError::PERCENT_OPERATOR_ERROR); 203 | ++i; 204 | *i = METACHARACTERS.at(">"); 205 | } 206 | } 207 | } 208 | } 209 | 210 | /** 211 | * 为了保证°的优先计算,对其及前面的数字加上括号 212 | */ 213 | void Expression::degreeOperatorPreprocessing() 214 | { 215 | //与对百分号处理类似,只是无需对后一个操作词进行判断,°无二义性 216 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 217 | { 218 | if ((*i).e == "`") 219 | { 220 | /* 221 | * 角度前只能为数字或括号包围的表达式 222 | */ 223 | --i; 224 | if(i->type!=0 && i->in_priority<=100) 225 | throw runtime_error(ExpressionError::DEGREE_OPERATOR_ERROR); 226 | ++i; 227 | } 228 | } 229 | } 230 | 231 | //将大/中操作转换为对应的小括号 232 | void Expression::bracketPreprocessing() 233 | { 234 | for (list::iterator i = exp.begin(); i != exp.end(); ++i) 235 | { 236 | //转换左括号 237 | if ((*i).out_priority ==101 || (*i).out_priority == 102) 238 | { 239 | i = exp.erase(i); 240 | i = exp.insert(i, METACHARACTERS.at("(")); 241 | } 242 | //转换右括号 243 | else if ((*i).in_priority == 101 || (*i).in_priority == 102) 244 | { 245 | i = exp.erase(i); 246 | i = exp.insert(i, METACHARACTERS.at(")")); 247 | } 248 | } 249 | } 250 | 251 | //对分割后的表达式进行预处理,便于接下来的操作 252 | void Expression::preprocessing() 253 | { 254 | negativeOperatorPreprocessing(); 255 | sqrtOperatorPreprocessing(); 256 | percentOperatorPreprocessing(); 257 | bracketPreprocessing(); 258 | degreeOperatorPreprocessing(); 259 | } 260 | 261 | void Expression::operation() 262 | { 263 | if (op.top().operand == 1) //若为一元运算符 264 | { 265 | double op1; if (op.empty()) 266 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 267 | else 268 | calc(op.top(), op1); 269 | } 270 | else //若为二元运算符 271 | { 272 | double op1, op2; 273 | if (op.empty()) 274 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 275 | else 276 | calc(op.top(), op1, op2); 277 | } 278 | op.pop(); 279 | } 280 | 281 | 282 | void Expression::transToPostfix() 283 | { 284 | try { 285 | exp.push_front(METACHARACTERS.at("$")); 286 | for (auto i : exp) 287 | { 288 | //如果当前元素为操作数,压入操作数栈 289 | if (i.type == 0) 290 | number.push(stod(i.e)); 291 | //如果当前元素为运算符,比较其与运算符栈顶元素的优先级 292 | else if (i.type == 1) 293 | { 294 | /* 295 | * 如果小于栈顶运算符优先级, 296 | * 不断出栈栈顶运算符直到栈顶运算符优先级小于当前运算符优先级, 297 | * 并依次对出栈的运算符进行运算 298 | * 然后入栈当前运算符 299 | */ 300 | if (i.out_priority <= op.top().in_priority) 301 | { 302 | do 303 | { 304 | operation(); 305 | } while (i.out_priority <= op.top().in_priority); 306 | } 307 | op.push(i); 308 | } 309 | //如果当前运算符为括号 310 | else if (i.type == 2) 311 | { 312 | //如果当前括号为左括号,入栈 313 | if (i.out_priority > 0) 314 | { 315 | op.push(i); 316 | //lastBracket = i; 317 | } 318 | //如果当前括号为右括号,出栈运算符栈直到遇到第一个左括号 319 | else if (i.out_priority < 0) 320 | { 321 | // //一对括号内无内容,抛出括号异常 322 | // if (op.top().out_priority>100) 323 | // throw runtime_error(ExpressionError::NEEDLESS_BARCKET_ERROR); 324 | 325 | while (op.top().type != 2) 326 | { 327 | operation(); 328 | } 329 | 330 | op.pop(); 331 | if (op.empty()) 332 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 333 | } 334 | } 335 | //表达式边缘标识符$直接压入运算符栈 336 | else if (i.type == 3) 337 | op.push(i); 338 | } 339 | 340 | //对运算符栈剩余的运算符依次出栈并进行运算 341 | while (op.size() > 1) 342 | { 343 | operation(); 344 | } 345 | 346 | if(number.size() > 1) 347 | { 348 | throw runtime_error(ExpressionError::MISSING_OPERATOR_ERROR); 349 | } 350 | } 351 | catch (...) { 352 | throw; 353 | } 354 | } 355 | 356 | //单目运算符运算 357 | void Expression::calc(Metacharacter mc, double & op1) 358 | { 359 | if (number.empty()) 360 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 361 | else 362 | { 363 | op1 = number.top(); 364 | number.pop(); 365 | } 366 | try { 367 | if (mc.e == "!") 368 | number.push(mathEx.op_factorial(op1)); 369 | else if (mc.e == "`") 370 | number.push(mathEx.op_degree_to_radian(op1)); 371 | else if (mc.e == ">") 372 | number.push(mathEx.op_percent(op1)); 373 | else if (mc.e == "<") 374 | number.push(mathEx.op_square_root(op1)); 375 | else if (mc.e == "sin") 376 | number.push(mathEx.op_sin(op1)); 377 | else if (mc.e == "cos") 378 | number.push(mathEx.op_cos(op1)); 379 | else if (mc.e == "tan") 380 | number.push(mathEx.op_tan(op1)); 381 | else if (mc.e == "arcsin") 382 | number.push(mathEx.op_arcsin(op1)); 383 | else if (mc.e == "arccos") 384 | number.push(mathEx.op_arccos(op1)); 385 | else if (mc.e == "arctan") 386 | number.push(mathEx.op_arctan(op1)); 387 | else if (mc.e == "log" || mc.e == "lg") 388 | number.push(mathEx.op_lg(op1)); 389 | else if (mc.e == "ln") 390 | number.push(mathEx.op_ln(op1)); 391 | else 392 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + mc.e); 393 | } 394 | catch (runtime_error) { 395 | throw; 396 | } 397 | 398 | } 399 | 400 | //双目运算符运算 401 | void Expression::calc(Metacharacter mc, double & op1, double & op2) 402 | { 403 | if (number.empty()) //数字栈为空,缺少操作数2 404 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 405 | else 406 | { 407 | op2 = number.top(); 408 | number.pop(); 409 | } 410 | if (number.empty()) //数字栈为空,缺少操作数1 411 | throw runtime_error(ExpressionError::MISSING_OPERAND_ERROR); 412 | else 413 | { 414 | op1 = number.top(); 415 | number.pop(); 416 | } 417 | try { 418 | if (mc.e == "+") 419 | number.push(mathEx.op_add(op1, op2)); 420 | else if (mc.e == "-") 421 | number.push(mathEx.op_subtract(op1, op2)); 422 | else if (mc.e == "*") 423 | number.push(mathEx.op_multiply(op1, op2)); 424 | else if (mc.e == "/") 425 | number.push(mathEx.op_divide(op1, op2)); 426 | else if (mc.e == "^") 427 | number.push(mathEx.op_pow(op1, op2)); 428 | else if (mc.e == "%") 429 | number.push(mathEx.op_mod(op1, op2)); 430 | else if (mc.e == "#") 431 | number.push(mathEx.op_extract_root(op1, op2)); 432 | else 433 | throw runtime_error(ExpressionError::ILLEGAL_CHARACTER_ERROR + mc.e); 434 | } 435 | catch (runtime_error) { 436 | throw; 437 | } 438 | } 439 | 440 | /* 441 | * 计算 442 | */ 443 | string Expression::getResult() 444 | { 445 | try { 446 | simpleCheck(); //字符合法性检查 447 | split(); //构字成词 448 | preprocessing(); //特殊运算符预处理 449 | transToPostfix(); //转换为逆波兰式并计算 450 | // for (auto &i : exp) 451 | // { 452 | // cout << i.e << ' '; 453 | // } 454 | } catch (runtime_error &){ 455 | throw; 456 | } 457 | result = number.top(); //数字栈中最后一个数即为结果 458 | return to_string(mathEx.getRound(result)); 459 | } 460 | 461 | 462 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------