大概描述

       用c++语言在vc中实现部分数学计算功能。其中实现的数学计算功能包括加减乘除运算、开方计算、自然对数运算、以10为底的对数运算、幂计算、正弦余弦计算。

由用户输入要计算的表达式,然后判断表达式是否含有未知变量,若含有未知变量则调用可以处理未知量的计算函数,否则调用一般的计算函数。

把用户输入的表达式存进一个存放中缀表达式的字符数组,再定义一个存放后缀表达式的字符数组,通过调用中缀转后缀的函数,将转为后缀的字符存进后缀表达式的字符数组。

用存放后缀表达式的字符数组调用计算函数,遇到数字时,调用读取数据的函数,把数字字符转换为double型的数。最后将答案输出。

为方便,对于未知量的处理,人为地规定了未知量的顺序和名字,规定如下:未知量的定义最多有5个,其名字和顺序如下x、y、z、m、n。

同时,为方便,常见函数的名字一律采用一个字母代替,其中sin函数用s代替,cos函数用c代替,ln函数用l代替,log10函数用g代替。

实验目的

1   用c++语言在vc中实现部分数学计算功能。其中实现的数学计算功能包括加减乘除运算、开方计算、自然对数       运算、以10为底的对数运算、幂计算、正弦余弦计算。

2   通过用户输入表达式,实现字符串的处理:实现中缀表达式转化后缀表达式,实现后缀表达式的数字字符的处       理。

3   实现后缀表达式的计算。

实验设计

1、由用户输入中缀表达式,把表达式存进一个字符数组,再定义一个字符数组用于存放后缀表达式

2、写一个将中缀表达式转为后缀表达式的函数,利用栈来处理操作符和括号

3、写一个从后缀表达式获取数据的函数

4、写一个函数,判断用户输入的表达式是否含有未知量

5、写两个计算函数,一个用于计算不含未知量的表达式,一个用于计算含有未知量的表达式

6、规定未知量的名字和顺序(本程序只定义了5个未知量,其名字依次为x、y、z、m、n)

7、调用<cmath>中的常见函数;如调用其正弦余弦函数对数函数等

实验描述

  1. 在主函数测试计算器,提示用户相应的函数名字缩写定义,提示用户输入表达式,并且创建两个字符数组,分别用于存放中缀  表达式和后缀表达式,再用这两个数组去调用中缀转后缀的函数,继而调用后缀表达式的计算函数,具体看main()函数。
  2. 中缀表达式转后缀表达式函数:创建一个字符型的栈,用于存放操作符。将存放中缀表达式的字符数组作为实参来调用此函数。然后从i=0开始读取字符数组里的元素,若遇到数字或者未知量,则调用读取数据的函数;若遇到函数缩写名时,则先将后面的数存进后缀表达式的数组,再将函数缩写名存进后缀表达式的数组;若遇到‘(’,则将其进栈;若遇到‘)’,则将栈顶的操作符存进后缀表达式的字符数组,并且出栈,直到遇到‘(’,将‘(’出栈;若遇到二目操作符,则比较此操作符和栈顶操作符的优先级,若栈顶操作符的优先级高,则将栈顶操作符放进后缀表达式,并将其出栈,一直进行此操作,直到栈里的操作符优先级比此操作符的优先级低。具体看getpostfix()函数。
  3. 获取操作符优先级的函数:加减的优先级定义为1,乘除的优先级定义为2,幂计算的优先级定义为3。具体看getpri()函数。
  4. 判断字符是否是二目操作符函数,具体看is_opr()函数。
  5. 判断字符是否是函数缩写名,具体看is_char()函数。
  6. 判断字符是否是数字或者未知量函数,具体看is_num()函数。
  7. 从后缀表达式读取数据函数:在读取后缀表达式的字符时,遇到数字,则调用此函数。调用此函数时,除了要传后缀表达式的数组做参数外,还要传此时的i的引用来做参数。具体看read_number()函数。
  8. 判断表达式是否含有未知量函数,具体看is_xyzmn()函数。
  9. 计算不含未知量表达式的函数:创建一个double型的数组,用于存放后缀表达式里的数据和进行计算后的中间结果。遍历存放后缀表达式的字符数组,若遇到数字,则调用读取数据的函数,并且把读取到的数据放在double型的数组中;若遇到操作符或者函数缩写名,则进行相应计算。具体看getpanswer()函数。
  10. 计算含有未知量表达式的函数: 计算含有未知量表达式的函数实现和计算不含未知量表达式的函数实现差不多。只不过在遍历后缀表达式数组时,若遇到未知量,则将未知量的值直接存进double型数据数组,而不存未知量。具体看geteanswer()函数。

完整代码

/*************************************************************************
> File Name: mycomputer.c
> Author: surecheun
> Mail: surecheun@163.com
> Created Time: 2017年4月18日
************************************************************************/ #include<iostream>
#include<stack>
#include<string>
#include<vector>
#include <sstream>
#include<cmath>
#define max 100 using namespace std; //对二目操作符进行优先级的量化转变
int getpri(char c) {
switch (c) {
case '+':return 1; break;
case '-':return 1; break;//‘+’和‘-’的优先级为最低级1
case '*':return 2; break;
case '/':return 2; break;//‘*’‘/’的优先级为中级2
case'^':return 3; break;//‘^’的优先级最高,为3
default:return 0; break;
}
}
//判断字符是否是二目操作符
int is_opr(char c)
{
switch (c) {
case '+':
case '-':
case '*':
case '/':
case'^':return 1; break;
default:return 0; break;
}
}
//判断字符是否是数字或者是未知量
int is_num(char c)
{
switch (c)
{
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
case'.':
case'x':
case'y':
case'z':
case'm':
case'n':
return 1; break;
default:return 0; break;
}
}
//判断字符是否代表特殊函数,为了程序简单,取特殊函数的某个字母代替该函数(此类函数均为单目运算)
int is_char(char c)
{
switch (c)
{
case's'://sin函数
case'c'://cos函数
case'q'://开方函数
case'l'://ln函数
case'g'://log10函数
return 1; break;
default:return 0; break;
}
} //中缀表达式改写成后缀表达式
void getpostfix(char *in, char *post)
{
stack<char> st;//创建一个字符类的栈,用于存放操作符
st.push('@');//村一个@进栈底,方便于最后判断栈里的操作符是否已经全部出栈
int i = 0;
int j = 0;
while (in[i] != '#')//‘#’为字符数组的最后一个元素
{
char ch = in[i];
if (is_num(ch))//判断是否是数字后者未知量,若是则把其放进后缀字符数组
{
post[j++] = ch;
i++;
}
else if (is_char(ch))//判断字符是否是常见(单目运算)函数的缩写,若是则将函数后面的数放进后缀字符数组,再将函数名缩写放进后缀数组
{
i++;
char ch1 = in[i];
while (is_num(ch1) == 1)
{
post[j++] = ch1;
i++;
ch1 = in[i];
}//把函数后面的数输进后缀字符数组
post[j++] = ' ';//用空格分开数和函数名
post[j++] = ch; //将函数名的缩写放进后缀表达式的数组
}
else //若字符是二目操作符或者是括号,则做以下操作
{
post[j++] = ' ';//用空格隔开操作符前后的数,便于后续读取
if (ch == '(')//如果字符是‘(’,则将字符进栈
{
st.push(ch); }
else if (ch == ')') //若字符是‘)’,则将栈中的字符输进后缀表达式的字符数组,直至遇到‘(’
{
ch = st.top();
while (ch != '(')
{
post[j++] = ch;
st.pop();
ch = st.top();
}
st.pop(); //将‘(’出栈 }
else//若字符是二目操作符‘则做以下操作
{
int thisPri = getpri(ch); //获取操作符的优先级
char prevOpt = st.top(); //获取栈顶操作符
int prevPri = getpri(prevOpt); //获取栈顶操作符的优先级
while (thisPri <= prevPri)//比较两者的优先级,若栈顶操作符的优先级高,则将栈顶操作符放进后缀表达式,并将其出栈
{
post[j++] = prevOpt;//将栈顶操作符放进后缀表达式
st.pop(); //将其出栈
prevOpt = st.top();//取栈中新栈顶的操作符
prevPri = getpri(prevOpt);//同理获取栈中新栈顶的操作符的优先级
}
st.push(ch); //把新的操作符进栈
}
i++;
}
} char ch = st.top();
while (ch != '@')
{
post[j++] = ch;
st.pop();
ch = st.top();
}//当栈底元素不是’@‘时,将栈顶元素放进后缀表达时的字符数组
post[j] = '\0';
}
//读取数据,将后缀表达式的字符数字转变为数
double read_number(char *dest, int *i)
{
double x = 0;
int num = 0;
int j;
while (dest[*i]<'0' || dest[*i]>'9') (*i)++;
while (dest[*i] >= '0'&&dest[*i] <= '9')
{
x = x * 10 + (dest[*i] - '0');
(*i)++;
} if (dest[*i] == '.')//遇到小数点,则计算后面的数字个数,用于判断要把数字除以多少个10
{
(*i)++;
while (dest[*i] >= '0'&&dest[*i] <= '9')
{
num++;
x = x * 10 + (dest[*i] - '0');
(*i)++;
}
}
for (j = 0; j < num; j++)
x = x / 10;
return x;
} //计算没有未知数的表达式
double getpanswer(char *dest)
{
double x[50];//创建一个数组,用于存放数据
int len = 0;
int i = 0;
while (dest[i] != '\0')//当字符数组中的字符不是’/0‘时
{
if (dest[i] >= '0'&&dest[i] <= '9')//遇到数字时
x[len++] = read_number(dest, &i);//调用读取数据函数,并且把i的地址传过去,这样i的值将会在函数调用后,也改变,从而使i跳到下一个类型的字符
else if (is_char(dest[i]) || is_opr(dest[i]))//假设字符是二目操作符,或者是函数名缩写,则进行计算
{
switch (dest[i])
{ case '+'://加法
x[len - 2] = x[len - 2] + x[len - 1];
len--;
i++;
break;
case '-'://加法
x[len - 2] = x[len - 2] - x[len - 1];
len--;
i++;
break;
case '*'://乘法
x[len - 2] = x[len - 2] * x[len - 1];
len--;
i++;
break;
case '/'://除法
x[len - 2] = x[len - 2] / x[len - 1];
len--;
i++;
break;
case'^'://幂运算
for (double i = 1; i < x[len - 1]; i++)
{
double y = x[len - 2];
x[len - 2] = x[len - 2] * y;
}
len--;
i++;
break;
case's'://sin函数
x[len - 1] = sin(x[len - 1]);
i++;
break;
case'c'://cos函数
x[len - 1] = cos(x[len - 1]);
i++;
break;
case'q'://开方函数
x[len - 1] = sqrt(x[len - 1]);
i++;
break;
case'l'://ln函数
x[len - 1] = log(x[len - 1]);
i++;
break;
case'g'://log10函数
x[len - 1] = log10(x[len - 1]);
i++;
break;
} }
else i++;
}
return x[len - 1]; }
//计算含有未知量的表达式
double geteanswer(char *dest, double x1, double y1, double z1, double m1, double n1)
{
double x[50];
int len = 0;
int i = 0;
while (dest[i] != '\0')
{
if (dest[i] >= '0'&&dest[i] <= '9')
x[len++] = read_number(dest, &i);
else if (dest[i] == 'x' || dest[i] == 'y' || dest[i] == 'z' || dest[i] == 'm' || dest[i] == 'n')//如果遇到未知量,则将未知量的值直接存进数据数组,而不存未知量
{
if (dest[i] == 'x')
x[len++] = x1;
else if (dest[i] == 'y')
x[len++] = y1;
else if (dest[i] == 'z')
x[len++] = z1;
else if (dest[i] == 'm')
x[len++] = m1;
else
x[len++] = n1;
i++;
}
else if (is_char(dest[i]) || is_opr(dest[i]))//遇到操作符或者函数名字缩写,则同不含有未知量的计算一样
{
switch (dest[i])
{ case '+':
x[len - 2] = x[len - 2] + x[len - 1];
len--;
i++;
break;
case '-':
x[len - 2] = x[len - 2] - x[len - 1];
len--;
i++;
break;
case '*':
x[len - 2] = x[len - 2] * x[len - 1];
len--;
i++;
break;
case '/':
x[len - 2] = x[len - 2] / x[len - 1];
len--;
i++;
break;
case'^':
for (double i = 1; i < x[len - 1]; i++)
{
double y = x[len - 2];
x[len - 2] = x[len - 2] * y;
}
len--;
i++;
break;
case's':
x[len - 1] = sin(x[len - 1]);
i++;
break;
case'c':
x[len - 1] = cos(x[len - 1]);
i++;
break;
case'q':
x[len - 1] = sqrt(x[len - 1]);
i++;
break;
case'l':
x[len - 1] = log(x[len - 1]);
i++;
break;
case'g':
x[len - 1] = log10(x[len - 1]);
i++;
break;
} }
else i++;
}
return x[len - 1];
} int is_xyzmn(char *d, int j)//判断表达式是否含有未知量
{
int p;
for (int o = 0; o < j; o++)
{
if (d[o] == 'x')
{
p = 1;
break;
}
else
p = 0;
}
return p;
} int main() {
cout << "sin请用s代替;cos请用c代替;sqrt请用q代替;ln用l代替;log10用g代替!" << endl;
cout << "如果表达式含有未知数,请按下面的顺序定义变量名字:x,y,z,m,n.(最多只允许5个变量)" << endl;
char infix[max];//创建一个字符数组,用于存放中缀表达式
char postfix[max];//创建一个字符数组,用于存放后缀表达式
int i = 0;
char ch;
while ((ch = getchar()) != '\n')
{
infix[i++] = ch;//把输入的字符放进中缀表达式的数组
}
infix[i++] = '#';//放进一个标志字符,便于判断中缀表达式是否已查完
infix[i] = '\0';
getpostfix(infix, postfix);//调用中缀转后缀函数
cout << "输出后缀表达式:" << postfix << endl;
double a;//用于存放答案 if (is_xyzmn(infix, i))//判断表达式是否含有未知量,若含有,则输入未知量的取值,并且调用含有未知量表达式的计算函数
{
cout << "请按顺序输入未知数的取值,若未知数不够5个,请用0补齐:";
double a1;
double a2;
double a3;
double a4;
double a5;
cin >> a1;
cin >> a2;
cin >> a3;
cin >> a4;
cin >> a5;
a = geteanswer(postfix, a1, a2, a3, a4, a5);//调用含有为质量的计算函数
}
if (!is_xyzmn(infix, i))//若表达式没有含未知量,则调用不含未知量的计算函数
a = getpanswer(postfix);//调用不含为质量的计算函数
cout << a << endl;//输出答案
getchar();
return 0;
}

欢迎指教!

C++实现计算器功能(包括计算含未知量的式子),输出后缀表达式的更多相关文章

  1. 栈的应用1——超级计算器(中缀与后缀表达式)C语言

    这里要学的程序主要用来实现一个功能——输入表达式输出结果,也就是一个计算器.效果如下: 这个程序主要有两个步骤:1.把中缀表达式转换为后缀表达式:2.计算后缀表达式的结果. 首先先明白几个问题: 1. ...

  2. 深入浅出数据结构C语言版(8)——后缀表达式、栈与四则运算计算器

    在深入浅出数据结构(7)的末尾,我们提到了栈可以用于实现计算器,并且我们给出了存储表达式的数据结构(结构体及该结构体组成的数组),如下: //SIZE用于多个场合,如栈的大小.表达式数组的大小 #de ...

  3. hdu-1237 简单计算器---中缀表达式转后缀表达式

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1237 题目大意: 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值. 思路 ...

  4. 利用PYTHON设计计算器功能

    通过利用PYTHON 设计处理计算器的功能如: 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 ))- (-4*3 ...

  5. javaWeb 使用 jsp 和 javaBean 实现计算器功能

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  6. C#实现按键计算器功能

    C#实现按键计算器功能 (一次失败的编程) 界面: 代码如下: using System; using System.Collections.Generic; using System.Compone ...

  7. 实现Linux下dc的功能,计算后缀表达式的值

    提交测试截图和码云练习项目链接,实现Linux下dc的功能,计算后缀表达式的值 -将运算符写在两个操作数之后的表达式称为"后缀表达式",如上面的中缀表达式可转换为后缀表达式1 2 ...

  8. Python-正则表达式实现计算器功能

    需求: 用户输入运算表达式,终端显示计算结果 源代码: # !/usr/bin/env/ python3 # -*- coding: utf-8 -*- """用户输入计 ...

  9. C# 一个计算器功能实现引发的思考

    一.需求 计算器功能需求,这个众所周知,很明确了. 二.步骤分析 1)初级实现计算器 static int Calculator(int a,int b,string str) { switch(st ...

随机推荐

  1. 自己实现strcpy函数

    #include //printf #include //ssert #include //malloc #include //strlen char * sstrcpy(char * strdst, ...

  2. java中ThreadLocalRandom类和Random类的使用

    package frank; import java.lang.*; import java.util.*;//工具类一般都在util里面 import java.util.concurrent.Th ...

  3. ZOJ 1364 Machine Schedule(二分图最大匹配)

    题意 机器调度问题 有两个机器A,B A有n种工作模式0...n-1 B有m种工作模式0...m-1 然后又k个任务要做 每一个任务能够用A机器的模式i或b机器的模式j来完毕 机器開始都处于模式0 每 ...

  4. Apache优化提高并发数量

    问题: 我们用lvs做了负载均衡.使用了两台server做login的服务.以及二次资源下载服务.可是在推广过程中.陆续有人反映server登录困难. 解决过程: 1.首先我们查看流量日志以及serv ...

  5. crontab用法

    在工作中有时需要定时执行某些操作,于是想到使用crontab来实现 crontab的用法: crontab file [-u user]    用指定的文件替代目前的crontab crontab - ...

  6. 华为HiAI 助力苏宁易购,让你尽享完美视觉购物体验!

    还在感慨商品照片与实物存在差距,又要退货? 还在抱怨被忽视的图片小细节,影响了生活品质? 想要“买买买”, 又担心海量的商品图片耗光你的流量? 就在近期 搭载HiAI能力的苏宁易购新版上线, 让你畅快 ...

  7. java 获取网页指定内容

    import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; ...

  8. Hibernate命名查询

    hibernate命名的查询是通过一些有意义的名称来使用查询的方式.就类似于使用别名一样. Hibernate框架提供命名查询的概念,以便应用程序员不需要将查询分散到所有的java代码,进一步提高代码 ...

  9. form表单提交方式

    form表单提交方式总结一下: 一.利用submit按钮实现提交,当点击submit按钮时,触发onclick事件,由JavaScript里函数判断输入内容是否为空,如果为空,返回false, 不提交 ...

  10. python django -5 进阶

    高级知识点包括: 静态文件处理 中间件 上传图片 Admin站点 分页 使用jquery完成ajax 管理静态文件 项目中的CSS.图片.js都是静态文件 配置静态文件 在settings 文件中定义 ...