|
同题,基于分治法实现,能够支持函数、括号
遵循 GPL 发布
dev-c++写成
欢迎大家使用,和提出意见建议
[code:1]
float calculate_exp(const char *str);
[/code:1]
计算表达式的函数,源代码中有说明
[code:1]
/*******************************************************************************
* main.cpp
*
* 功能:主程序源文件
* 作者: cpp <[email protected]>
* 维护:cpp <[email protected]>
*
* 这是 X-Calculator 的一部分,遵循 GNU General Public Lisence (GPL) 发布
* 任何人可以发 email 给作者,以取得最新的源代码
*******************************************************************************/
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
/*******************************************************************************
*
* 计算表达式
*
* 参数
* const char *str: 指向表达式字符串的指针
*
* 返回值: 运算结果
*
*******************************************************************************/
float calculate_exp(const char *str);
/*******************************************************************************
* 计算两个数的和/差/积/商
*
* 参数
* float num1: 第一个数
* float num2: 第二个数
* char op: 运算符,可以为 '+' '-' '*' '/'
*
* 返回值: 运算结果
*******************************************************************************/
float calculate_num(float num1, float num2, char op);
/*******************************************************************************
* 计算表达式,与 calculate_str 形成间接递归
*
* 参数
* const char *str:
*
* 返回值: 运算结果
*******************************************************************************/
float calculate_func(const char *str);
/*******************************************************************************
* 找到最后运算的运算符
*
* 参数
* const char *str: 指向表达式的字符串
*
* 返回值: 指向最后一个运算符的指针
*******************************************************************************/
const char * find_last_op(const char *str);
/*******************************************************************************
* 返回一个浮点数的位数 (包含小数点,例如: num_len(1.234) 返回 5)
*
* 参数
* float n:
*
* 返回值: 位数
*******************************************************************************/
int num_len(float n);
int main(int argc, char* argv[])
{
while (1) {
char str[256];
cin.getline(str, 256);
cout << calculate_exp(str) << endl;
}
return 0;
}
int num_len(float n)
{
/*
* 将 n 转换成字符串,返回该字符串的长度
*/
char str[256] = {0};
char *p;
sprintf(str, "%f", n);
p = str + strlen(str) - 1;
while (*p == '0' && p >= str)
*p-- = 0;
p = str + strlen(str) - 1;
if (*p == '.')
*p = 0;
return strlen(str);
}
const char *find_last_op(const char *str)
{
int len = strlen(str);
int n = 0;
while (len > 0) {
if ((str[len] == '+' || str[len] == '-') && n == 0)
return str + len;
if (str[len] == '(')
n--;
else if (str[len] == ')')
n++;
len--;
}
len = strlen(str);
n = 0;
while (len > 0) {
if ((str[len] == '*' || str[len] == '/') && n == 0)
return str + len;
if (str[len] == '(')
n--;
else if (str[len] == ')')
n++;
len--;
}
len = strlen(str);
n = 0;
while (len > 0) {
if (str[len] == '^' && n == 0)
return str+len;
if (str[len] == '(')
n--;
else if (str[len] == ')')
n++;
len--;
}
return NULL;
}
float calculate_exp(const char *str)
{
/*
* 递归调用;
* 如果 str 不包含运算符,例如 str = "1.1",将 str 转换成小数,返回;
* 如果 str 包含运算符,找到最后运算的运算符,分成左右两个表达式,
* 递归调用 calculate (一个表达式可以分成: [左表达式] [运算符] [右表达式]);
*/
if (find_last_op(str) == NULL && str[0] != '('
&& (str[0] >= '0' && str[0] <= '9' || str[0] == '+' || str[0] == '-')) { // 中止条件
return atof(str);
}
else if ((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z')
&& find_last_op(str) == NULL) {
return calculate_func(str);
}
else {
const char *last_op = find_last_op(str); // 找到最后运算的运算符
const char *p = str;
int n = 0; // stack
if (last_op != NULL) {
while (p != last_op) {
if (*p == '(') n++;
else if (*p == ')') n--;
p++;
}
}
if (n != 0 || last_op == NULL) { // last_op 在括号内 或者 括号内根本没有运算符
/*
* 脱括号,递归调用
*/
char tmp[256] = {0};
strncpy(tmp, str + 1, strlen(str) - 2);
return calculate_exp(tmp);
}
else { // last_op 在括号外
/*
* 把 last_op 两边的表达式分别计算,在合并结果
*/
char left_str[256] = {0}, right_str[256] = {0};
strncpy(left_str, str, last_op - str);
strcpy(right_str, last_op + 1);
return calculate_num(calculate_exp(left_str),
calculate_exp(right_str), *last_op);
}
}
}
float calculate_num(float num1, float num2, char op)
{
switch (op) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
return num1 / num2;
case '^':
return pow(num1, num2);
default:
return 0;
}
}
float calculate_func(const char *exp)
{
char *l = NULL, *r = NULL;
char *p = NULL;
int n = 1; // stack
float ret = 0;
char str[256] = {0};
strncpy(str, exp, 256);
l = strchr(str, '(');
p = l + 1;
while (*p != 0) {
if (*p == '(' && n != 0)
n++;
else if (*p == ')' && n != 0)
n--;
if (*p == ')' && n == 0) {
r = p;
break;
}
p++;
}
*r = 0;
ret = calculate_exp(l+1);
*l = 0;
if (strcmp(str, "sqrt") == 0)
return sqrt(ret);
else if (strcmp(str, "sin") == 0)
return sin(ret / 360 * 2 * M_PI);
else if (strcmp(str, "cos") == 0)
return cos(ret / 360 * 2 * M_PI);
else if (strcmp(str, "tan") == 0 || strcmp(str, "tg") == 0)
return tan(ret / 360 * 2 * M_PI);
else if (strcmp(str, "cot") == 0 || strcmp(str, "ctg") == 0)
return 1 / tan(ret / 360 * 2 * M_PI);
}
[/code:1] |
|