C语言 算术表达式
2008-09-09 23:45
274 查看
算术表达式的计算在我们日常的运用中是十分广泛的,特别是对于基本的四则混合运算的表达式。在我们习惯的计算表达方式中,一般来说是中缀表达式类型的。
中缀表达式的计算比较复杂,它必须遵守以下三条规则:
(1) 先计算括号内,后计算括号外;
(2) 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级;
(3) 同一优先级运算,从左向右依次进行。
中缀表达式符合我们一般的习惯,但是在计算机的计算中,它实现的时候比较复杂,要考虑的因素比较多。为了方便进行计算,我们可以采用后缀表达式来进行计算,因为这个类型的表达式更符合计算机的口味吧(这个是波兰科学家卢卡谢维奇提出的,扯远了:-))
//计算公式中缀表达式转后缀表达式算法
int Offpos(char *str)
{
if (!str)
return -1 ;
int pos = 0 ;
while (*str) {
if ( ('+' == *str) ||
('-' == *str) ||
('*' == *str) ||
('/' == *str) ||
('@' == *str) ||
(')' == *str) ||
('!' == *str))
break ;
if (((*str >= '0') && (*str <= '9'))
|| ('.' == *str)) {
pos++ ;
str++ ;
}
else {
return -1 ;
}
}
return pos ;
}
//转化为后缀算术表达式
char *Prase(char *datas, char *str)
{
if (!str || '@' != *str)
return NULL ;
//假设用来处理符合的堆栈
char symbol[1024] = { 0 } ;
char *value = NULL ;
char *sign = NULL ;
value = datas ;
sign = symbol ;
int pos = 0 ;
char c ;
*sign++ = *str ;
*value++ = *str ;
//处理一些负数的情况
if (('@' == *str) && ('-' == *(str+1))) {
*value++ = '0' ;
*value++ = '!' ;
}
str++ ;
c = *str ;
while (*str) {
switch (*str) {
//@字符串结束,弹出所有的操作符
case '@' :
4000
c = *(sign - 1) ;
if (c != '@') {
sign-- ;
while (*sign != '@') {
*value++ = *sign-- ;
*value++ = '!' ;
}
}
break ;
//'('符合进入堆栈
case '(' :
*sign++ = '(' ;
break ;
//弹出到'('为止的所有符号堆栈里面的字符
case ')' :
//to do ;
sign-- ;
while ('(' != *sign) {
if ('@' == *sign)
return NULL ;
*value++ = *sign ;
*value++ = '!' ;
sign-- ;
}
*sign = 0 ;
break ;
case '-' :
c = *(str-1) ;
//如果 '-' 的意义表示负号
if ( c == '-' ||
c == '(' ||
c == '+' ||
c == '*' ||
c == '/') {
*value++ = '-' ;
break ;
}
//如果 '-' 的意义表示负号
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = *str ;
break ;
}
//弹出所有的堆栈符号
sign-- ;
while (!(('@' == *sign) || ('(' == *sign))) {
c = *sign ;
*value++ = c ;
*value++ = '!' ;
sign-- ;
}
sign++ ;
*sign++ = *str ;
break ;
case '+' :
//+符号不做那么严格的处理了
c = *str ;
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = c ;
break ;
}
sign-- ;
while (!(('@' == *sign) || ('(' == *sign))) {
c = *sign ;
*value++ = c ;
*value++ = '!' ;
sign-- ;
}
sign++ ;
*sign++ = *str ;
break ;
case '*' :
case '/' :
//这两个的符号优先级别比+-高
c = *str ;
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = c ;
break ;
}
c = *(sign - 1) ;
if (('+' == c) || ('-' == c)) {
*sign++ = *str ;
}
if (('*' == c) || ('/' == c)) {
*value++ = c ;
*value++ = '!' ;
sign-- ;
*sign++ = *str ;
}
break ;
default :
//默认数据值压入堆栈
if ((*str >= '0') && (*str <= '9')) {
pos = Offpos(str) ;
strncpy(value, str, pos) ;
str += pos ;
value += pos ;
*value++ = '!' ;
}
str-- ;
break ;
}
str++ ;
}
return datas ;
}
计算后缀表达式的算法
//计算公式
float Calculate(char *str)
{
if (!str)
return -1.0 ;
if ('@' != *str)
return -1.0 ;
str++ ;
float datas[1024] = { 0.0 } ;
float f = 0.0 ;
float *temp = datas ;
int pos = 0 ;
while (*str) {
switch (*str) {
case '@' :
break ;
case '+' :
f = *(--temp) ;
temp-- ;
*temp += f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
case '-' :
//处理负号的问题
if ((*(str+1) >= '0') && (*(str+1) <= '9')) {
f = atof(str) ;
str++ ;
pos = Offpos(str) ;
//pos++ ;
str += pos ;
// str-- ;
*temp++ = f ;
}
else {
f = *(--temp) ;
temp-- ;
*temp -= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
}
break ;
case '*' :
f = *(--temp) ;
temp-- ;
*temp *= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
case '/' :
f = *(--temp) ;
temp-- ;
//如果分母是0
if ((f > -(1e-6)) && (f < 1e-6))
return -1 ;
*temp /= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
default :
if ((*str >= '0') && (*str <= '9')) {
f = atof(str) ;
pos = Offpos(str) ;
str += pos ;
*temp++ = f ;
// str-- ;
}
break ;
}
str++ ;
}
return *(--temp) ;
}
主函数代码
int main(int argc, char* argv[])
{
char datas[1024] = { 0 } ;
char temp[] = "@-(20+-23*4)/(-1-20/2)@" ;
float f = 0.0 ;
Prase(datas, temp) ;
f = Calculate(datas) ;
return 0;
}
程序写得有点乱,经过我简单的测试,目前还没有发现什么问题,如果大家有什么好的建议都可以告诉我o(∩_∩)o...哈哈,还有个问题,就是我把分母是0的时候整个表达式返回值改成了-1.0。
对应精度的问题会引发比较严重的错误,比如说(0.9-0.8-0.1)*100000000000结果不是我们想希望的。
参考文章
http://www.cnblogs.com/ZHOULONG/archive/2008/04/04/1137833.html http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html
中缀表达式的计算比较复杂,它必须遵守以下三条规则:
(1) 先计算括号内,后计算括号外;
(2) 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级;
(3) 同一优先级运算,从左向右依次进行。
中缀表达式符合我们一般的习惯,但是在计算机的计算中,它实现的时候比较复杂,要考虑的因素比较多。为了方便进行计算,我们可以采用后缀表达式来进行计算,因为这个类型的表达式更符合计算机的口味吧(这个是波兰科学家卢卡谢维奇提出的,扯远了:-))
//计算公式中缀表达式转后缀表达式算法
int Offpos(char *str)
{
if (!str)
return -1 ;
int pos = 0 ;
while (*str) {
if ( ('+' == *str) ||
('-' == *str) ||
('*' == *str) ||
('/' == *str) ||
('@' == *str) ||
(')' == *str) ||
('!' == *str))
break ;
if (((*str >= '0') && (*str <= '9'))
|| ('.' == *str)) {
pos++ ;
str++ ;
}
else {
return -1 ;
}
}
return pos ;
}
//转化为后缀算术表达式
char *Prase(char *datas, char *str)
{
if (!str || '@' != *str)
return NULL ;
//假设用来处理符合的堆栈
char symbol[1024] = { 0 } ;
char *value = NULL ;
char *sign = NULL ;
value = datas ;
sign = symbol ;
int pos = 0 ;
char c ;
*sign++ = *str ;
*value++ = *str ;
//处理一些负数的情况
if (('@' == *str) && ('-' == *(str+1))) {
*value++ = '0' ;
*value++ = '!' ;
}
str++ ;
c = *str ;
while (*str) {
switch (*str) {
//@字符串结束,弹出所有的操作符
case '@' :
4000
c = *(sign - 1) ;
if (c != '@') {
sign-- ;
while (*sign != '@') {
*value++ = *sign-- ;
*value++ = '!' ;
}
}
break ;
//'('符合进入堆栈
case '(' :
*sign++ = '(' ;
break ;
//弹出到'('为止的所有符号堆栈里面的字符
case ')' :
//to do ;
sign-- ;
while ('(' != *sign) {
if ('@' == *sign)
return NULL ;
*value++ = *sign ;
*value++ = '!' ;
sign-- ;
}
*sign = 0 ;
break ;
case '-' :
c = *(str-1) ;
//如果 '-' 的意义表示负号
if ( c == '-' ||
c == '(' ||
c == '+' ||
c == '*' ||
c == '/') {
*value++ = '-' ;
break ;
}
//如果 '-' 的意义表示负号
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = *str ;
break ;
}
//弹出所有的堆栈符号
sign-- ;
while (!(('@' == *sign) || ('(' == *sign))) {
c = *sign ;
*value++ = c ;
*value++ = '!' ;
sign-- ;
}
sign++ ;
*sign++ = *str ;
break ;
case '+' :
//+符号不做那么严格的处理了
c = *str ;
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = c ;
break ;
}
sign-- ;
while (!(('@' == *sign) || ('(' == *sign))) {
c = *sign ;
*value++ = c ;
*value++ = '!' ;
sign-- ;
}
sign++ ;
*sign++ = *str ;
break ;
case '*' :
case '/' :
//这两个的符号优先级别比+-高
c = *str ;
if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
*sign++ = c ;
break ;
}
c = *(sign - 1) ;
if (('+' == c) || ('-' == c)) {
*sign++ = *str ;
}
if (('*' == c) || ('/' == c)) {
*value++ = c ;
*value++ = '!' ;
sign-- ;
*sign++ = *str ;
}
break ;
default :
//默认数据值压入堆栈
if ((*str >= '0') && (*str <= '9')) {
pos = Offpos(str) ;
strncpy(value, str, pos) ;
str += pos ;
value += pos ;
*value++ = '!' ;
}
str-- ;
break ;
}
str++ ;
}
return datas ;
}
计算后缀表达式的算法
//计算公式
float Calculate(char *str)
{
if (!str)
return -1.0 ;
if ('@' != *str)
return -1.0 ;
str++ ;
float datas[1024] = { 0.0 } ;
float f = 0.0 ;
float *temp = datas ;
int pos = 0 ;
while (*str) {
switch (*str) {
case '@' :
break ;
case '+' :
f = *(--temp) ;
temp-- ;
*temp += f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
case '-' :
//处理负号的问题
if ((*(str+1) >= '0') && (*(str+1) <= '9')) {
f = atof(str) ;
str++ ;
pos = Offpos(str) ;
//pos++ ;
str += pos ;
// str-- ;
*temp++ = f ;
}
else {
f = *(--temp) ;
temp-- ;
*temp -= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
}
break ;
case '*' :
f = *(--temp) ;
temp-- ;
*temp *= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
case '/' :
f = *(--temp) ;
temp-- ;
//如果分母是0
if ((f > -(1e-6)) && (f < 1e-6))
return -1 ;
*temp /= f ;
temp++ ;
*temp = 0.0 ;
str++ ;
break ;
default :
if ((*str >= '0') && (*str <= '9')) {
f = atof(str) ;
pos = Offpos(str) ;
str += pos ;
*temp++ = f ;
// str-- ;
}
break ;
}
str++ ;
}
return *(--temp) ;
}
主函数代码
int main(int argc, char* argv[])
{
char datas[1024] = { 0 } ;
char temp[] = "@-(20+-23*4)/(-1-20/2)@" ;
float f = 0.0 ;
Prase(datas, temp) ;
f = Calculate(datas) ;
return 0;
}
程序写得有点乱,经过我简单的测试,目前还没有发现什么问题,如果大家有什么好的建议都可以告诉我o(∩_∩)o...哈哈,还有个问题,就是我把分母是0的时候整个表达式返回值改成了-1.0。
对应精度的问题会引发比较严重的错误,比如说(0.9-0.8-0.1)*100000000000结果不是我们想希望的。
参考文章
http://www.cnblogs.com/ZHOULONG/archive/2008/04/04/1137833.html http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html
相关文章推荐
- 《C语言及程序设计》实践项目——算术运算符与算术表达式
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践11——如何买玫瑰
- C语言初步-第11讲:算术运算符与算术表达式(分离整数和小数部分)
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践12——玩数字
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践13——坐标转换
- 详解C语言中的符号常量、变量与算术表达式
- c语言学习之基础知识点介绍(四):算术运算符和逗号表达式
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践9——分离各位数
- C语言初步-第11讲:算术运算符与算术表达式(分离各位数)
- C语言中的算术运算符和算术表达式
- 栈的操作和c语言实现算术表达式求值
- c语言算术运算表达式与赋值运算表达式的类型转换规则
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践10——分离整数和小数部分
- C语言初步-第11讲:算术运算符与算术表达式(如何买玫瑰?)
- C语言算术运算符和算术表达式
- C语言:算术运算符与算术表达式
- 重温C语言(1)----计算算术表达式的值
- C语言及程序设计初步例程-11 算术运算符与算术表达式
- C语言算术运算符和算术表达式
- c语言算术运算符和算术表达式整理学习