一、设计目标
设计一个支持连续计算的科学计算器。通过单击按钮,或者从文本框输入运算表达式,并完成计算,并且将结果显示出来。例如4*5+3,3+2/3,n的阶乘,x的y次幂,开平方,三角函数,log,ln,清除后退,显示历史记录等等。
二、算法分析
进行输入时直接输入到显示框上,当按下“=”按钮时读取显示框里的表达式,进行计算,并将结果输出到显示屏上。所以,计算器的核心算法就在于如何计算从显示屏上读取的中缀表达式。
计算中缀表达式需要用到两个栈Stack,一个作为数字栈number_stack,专门存储中缀表达式里面的数字,另一个是操作符栈operator_stack,用来存储操作符。核心算法是中缀表达式转成后缀表达式,然后计算后缀表达式,但是这俩个可以合起来一块计算。具体算法流程如下:
首先对涉及到的操作符设置优先级。从左至右依次读取中缀表达式,如果是数字(直接读出负数、小数、多于十位的数)则直接压入数字栈number_stack。如果是操作符(不包括左右括号),观察operator_stack是否为空,为空则直接压入栈,不为空则比较当前栈顶与此操作符的优先级。若此操作符优先级高则直接压入栈,否则弹出栈顶,并从数字栈number_stack弹出两个数字,第一个弹出的数字作为右操作数,第二个弹出的作为左操作数,与操作符运算并将结果压入栈。(若弹出的操作符为单目运算符,则只弹出一个数字)
如果碰到“(”直接入栈,碰到“)”从操作符栈operator_stack一直弹出,直到弹出“(”。到中缀表达式读取完后,看操作符栈operator_stack是否为空,不为空就依次弹出栈,直到为空。此时数字栈
number_satck剩余的一个数就是结果,将结果输出到显示屏上。
下面为流程图:
三、源代码
calculate.h
#ifndef CALCULATE_H
#define CALCULATE_H
#include<iostream>
#include<string>
#include<stack>
#include<math.h>
using namespace std;
class calculate
{
public:
calculate();
};
extern bool is_new;
extern bool is_minus;
extern double ans;
extern double e;
int getPriority(char ch);//得到运算符的优先级
void calculate(stack<double> &mystack, char operation);//根据操作符进行计算
double calculator(string str);//遍历表达式
#endif // CALCULATE_H
calculate.cpp
#include "calculate.h"
#include<iostream>
#include<string>
#include<stack>
#include<math.h>
using namespace std;
calculate::calculate()
{
}
bool is_new = false;
bool is_minus = false;
double ans = 0;
double e = 2.718281828459045;
double P = 3.14159265358979323846;
int getPriority(char ch)//得到运算符优先级
{
if (ch == '+' || ch == '-') return 1;
else if (ch == '*' || ch == '/') return 2;
else if (ch == 's' || ch == 'c'|| ch == 't' || ch == 'i' || ch == 'o' || ch == 'a' || ch == '^' || ch == 'g' || ch == 'n' || ch == 'r' || ch == 'm') return 3;
else if (ch == '!') return 4;
else return 5;
}
void calculate(stack<double> &number, char tmp_operation)//运算符计算函数
{
double num1, num2, num3;
num2 = number.top();
number.pop();
if(tmp_operation == '!'){
num3 = 1;
while(num2>1){
num3 *= num2;
num2 --;
}
}
else if(tmp_operation == 's' || tmp_operation == 'c' || tmp_operation == 't' || tmp_operation == 'i' || tmp_operation == 'o' || tmp_operation == 'a' || tmp_operation == 'g' || tmp_operation == 'n' || tmp_operation == 'r'){
if(tmp_operation == 's')num3 = sin(num2);
else if(tmp_operation == 'c')num3 = cos(num2);
else if(tmp_operation == 't')num3 = tan(num2);
else if(tmp_operation == 'i')num3 = asin(num2);
else if(tmp_operation == 'o')num3 = acos(num2);
else if(tmp_operation == 'a')num3 = atan(num2);
else if(tmp_operation == 'g')num3 = log10(num2);
else if(tmp_operation == 'n')num3 = log(num2);
else if(tmp_operation == 'r')num3 = sqrt(num2);
}
else{
num1 = number.top();
number.pop();
if (tmp_operation == '+') {
num3 = num1 + num2;
}
else if (tmp_operation == '-') {
num3 = num1 - num2;
}
else if (tmp_operation == '*') {
num3 = num1 * num2;
}
else if (tmp_operation == '/') {
num3 = num1 / num2;
}
else if (tmp_operation == '^') {
num3 = pow(num1, num2);
}
else if (tmp_operation == 'm'){
num3 = fmodf(num1, num2);
}
}
number.push(num3);
}
double calculator(string str)//遍历表达式
{
stack<double> number;
stack<char> operation;
int i = 0, j;
int size = str.size();
char tmp_operation;
string num;
string num0;
while (i < size) {
if (str[i] >= '0' && str[i] <= '9') {
j = i;
while ((j < size && str[j] >= '0' && str[j] <= '9') || str[j]=='.') { j++; }
num = str.substr(i, j - i);
if(!is_minus) number.push(atof(num.c_str()));
else number.push(0-atof(num.c_str()));
i = j;
}
else if (str[i] == 'A'){
number.push(ans);
i+=3;
}
else if(str[i] == 'e'){
number.push(e);
i++;
}
else if(str[i] == 'P'){
number.push(P);
i+=2;
}
else if(str[i] == '(' || str[i] == ')'){
if (str[i] == '(') operation.push(str[i]);
else {
while (operation.top() != '(') {
tmp_operation = operation.top();
operation.pop();
calculate(number, tmp_operation);
}
operation.pop();
}
i++;
}
else if(str[i] == 's' || str[i] == 'c' || str[i] == 't'){
if(str[i] == 's' && str[i+1] == 'q'){
operation.push('r');
i += 4;
}
else{
operation.push(str[i]);
i += 3;
}
}
else if(str[i] == 'a'){
if(str[i+3]=='s')operation.push('i');
else if(str[i+3]=='c')operation.push('o');
else if(str[i+3]=='t')operation.push('a');
i += 6;
}
else if(str[i] == 'l'){
if(str[i+1] == 'o'){operation.push('g');i+=3;}
else if(str[i+1]=='n'){operation.push('n');i+=2;}
}
else{
if(str[i]=='-' && (operation.empty() || operation.top()=='(')){
is_minus = true;
}
else if (operation.empty()) {
operation.push(str[i]);
}
else {
while (!operation.empty()) {
tmp_operation = operation.top();
if (getPriority(tmp_operation) >= getPriority(str[i])) {
operation.pop();
calculate(number, tmp_operation);
}
else break;
}
operation.push(str[i]);
}
if(str[i] == 'm')i += 3;
else i++;
}
}
while (!operation.empty()) {
tmp_operation = operation.top();
operation.pop();
calculate(number, tmp_operation);
}
return number.top();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<calculate.h>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_mul_clicked();
void on_pushButton_div_clicked();
void on_pushButton_sub_clicked();
void on_pushButton_add_clicked();
void on_pushButton_pow_clicked();
void on_pushButton_point_clicked();
void on_pushButton_0_clicked();
void on_pushButton_1_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_pushButton_6_clicked();
void on_pushButton_7_clicked();
void on_pushButton_8_clicked();
void on_pushButton_9_clicked();
void on_pushButton_del_clicked();
void on_pushButton_AC_clicked();
void on_pushButton_equ_clicked();
void on_pushButton_Ans_clicked();
void on_pushButton_left_clicked();
void on_pushButton_right_clicked();
void on_pushButton_pi_clicked();
void on_pushButton_sin_clicked();
void on_pushButton_cos_clicked();
void on_pushButton_tan_clicked();
void on_pushButton_1x_clicked();
void on_pushButton_n1_clicked();
void on_pushButton_squ_clicked();
void on_pushButton_e_clicked();
void on_pushButton_arcsin_clicked();
void on_pushButton_arccos_clicked();
void on_pushButton_arctan_clicked();
void on_pushButton_log_clicked();
void on_pushButton_ln_clicked();
void on_pushButton_x2_clicked();
void on_pushButton_x3_clicked();
void on_pushButton_ex_clicked();
void on_pushButton_2x_clicked();
void on_pushButton_mod_clicked();
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QLineEdit>
#include<QString>
#include<QByteArray>
#include<stdlib.h>
#include"calculate.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->line, SIGNAL(editingFinished()), this, SLOT(on_pushButton_equ_clicked()));
QFont font;
font.setPointSize(16);
ui->line->setFont(font);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_equ_clicked()
{
string str = ui->line->text().toStdString();
ans = calculator(str);
ui->line->setText(QString::number(ans));
is_new = true;
ui->textEdit->append(QString::fromStdString(str) + "=" + QString::number(ans));
}
void Widget::on_pushButton_del_clicked()
{
if(is_new){ui->line->setText("");}
QString a = ui->line->text();
if(a.right(6)=="arcsin" || a.right(6)=="arccos" || a.right(6)=="arctan") a.chop(6);
else if(a.right(3)=="sin" || a.right(3)=="cos" || a.right(3)=="tan" || a.right(3)=="Ans" || a.right(3)=="mod" || a.right(3)=="log") a.chop(3);
else if(a.right(4)=="sqrt") a.chop(4);
else if(a.right(2)=="ln" || a.right(2)=="PI") a.chop(2);
else a.chop(1);
ui->line->setText(a);
is_new = false;
}
void Widget::on_pushButton_mul_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'*');
is_new = false;
}
void Widget::on_pushButton_div_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'/');
is_new = false;
}
void Widget::on_pushButton_sub_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'-');
is_new = false;
}
void Widget::on_pushButton_add_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'+');
is_new = false;
}
void Widget::on_pushButton_pow_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'^');
is_new = false;
}
void Widget::on_pushButton_point_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'.');
is_new = false;
}
void Widget::on_pushButton_0_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'0');
is_new = false;
}
void Widget::on_pushButton_1_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'1');
is_new = false;
}
void Widget::on_pushButton_2_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'2');
is_new = false;
}
void Widget::on_pushButton_3_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'3');
is_new = false;
}
void Widget::on_pushButton_4_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'4');
is_new = false;
}
void Widget::on_pushButton_5_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'5');
is_new = false;
}
void Widget::on_pushButton_6_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'6');
is_new = false;
}
void Widget::on_pushButton_7_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'7');
is_new = false;
}
void Widget::on_pushButton_8_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'8');
is_new = false;
}
void Widget::on_pushButton_9_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'9');
is_new = false;
}
void Widget::on_pushButton_AC_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText("");
is_new = false;
}
void Widget::on_pushButton_Ans_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +"Ans");
is_new = false;
}
void Widget::on_pushButton_left_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +'(');
is_new = false;
}
void Widget::on_pushButton_right_clicked()
{
if(is_new){ui->line->setText("");}
ui->line->setText(ui->line->text() +')');
is_new = false;
}
void Widget::on_pushButton_pi_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"PI");
}
void Widget::on_pushButton_sin_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"sin");
}
void Widget::on_pushButton_cos_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"cos");
}
void Widget::on_pushButton_tan_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"tan");
}
void Widget::on_pushButton_1x_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"1/");
}
void Widget::on_pushButton_n1_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"!");
}
void Widget::on_pushButton_squ_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"sqrt");
}
void Widget::on_pushButton_e_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +'e');
}
void Widget::on_pushButton_arcsin_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"arcsin");
}
void Widget::on_pushButton_arccos_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"arccos");
}
void Widget::on_pushButton_arctan_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"arctan");
}
void Widget::on_pushButton_log_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"log");
}
void Widget::on_pushButton_ln_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"ln");
}
void Widget::on_pushButton_x2_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"^2");
}
void Widget::on_pushButton_x3_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"^3");
}
void Widget::on_pushButton_ex_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"e^");
}
void Widget::on_pushButton_2x_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"2^");
}
void Widget::on_pushButton_mod_clicked()
{
if(is_new){ui->line->setText("");}
is_new = false;
ui->line->setText(ui->line->text() +"mod");
}
void Widget::on_pushButton_clicked()
{
ui->textEdit->setText("");
}