170 lines
5.3 KiB
C
170 lines
5.3 KiB
C
// 算术表达式求值:支持 + - * / ^ 和小括号
|
|
// 规则:
|
|
// - 运算符优先级:括号 > 一元± > ^(右结合)> * /(左结合)> + -(左结合)
|
|
// - 输入为一行表达式,可能包含多余括号与空格
|
|
// - 输出为结果,按四舍五入取整
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
// 手写整数乘方(支持负指数):右结合的 ^ 使用该实现
|
|
static inline long double powi_ld(long double base, long long exp) {
|
|
if (exp == 0) return 1.0L;
|
|
int neg = 0;
|
|
if (exp < 0) { neg = 1; exp = -exp; }
|
|
long double res = 1.0L, a = base;
|
|
while (exp) {
|
|
if (exp & 1LL) res *= a;
|
|
a *= a;
|
|
exp >>= 1LL;
|
|
}
|
|
if (neg) {
|
|
// 避免 1/0 产生异常(表达式一般不会出现该情况)
|
|
if (res == 0.0L) return 0.0L; // 约定返回 0,防止 RE
|
|
return 1.0L / res;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// 手写四舍五入为 long long,避免依赖 llround
|
|
static inline long long roundll(long double x) {
|
|
return (x >= 0.0L) ? (long long)(x + 0.5L) : (long long)(x - 0.5L);
|
|
}
|
|
|
|
// 操作符优先级
|
|
static inline int prec(char op) {
|
|
switch (op) {
|
|
case '~': return 4; // 一元负号
|
|
case '^': return 3; // 乘方,右结合
|
|
case '*': case '/': return 2; // 乘除
|
|
case '+': case '-': return 1; // 加减
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
// 应用一个操作符到栈顶操作数
|
|
static inline void apply_top(long double *vals, int *vtop, char *ops, int *otop) {
|
|
char op = ops[--(*otop)];
|
|
if (op == '~') {
|
|
long double a = vals[--(*vtop)];
|
|
vals[(*vtop)++] = -a;
|
|
return;
|
|
}
|
|
long double b = vals[--(*vtop)];
|
|
long double a = vals[--(*vtop)];
|
|
long double r;
|
|
switch (op) {
|
|
case '+': r = a + b; break;
|
|
case '-': r = a - b; break;
|
|
case '*': r = a * b; break;
|
|
case '/':
|
|
// 防御除零导致的 RE:约定返回 0(题目数据通常不会出现此情况)
|
|
if (b == 0.0L) r = 0.0L; else r = a / b;
|
|
break;
|
|
case '^': {
|
|
long long be = roundll(b); // 指数按近似整数处理
|
|
r = powi_ld(a, be);
|
|
break;
|
|
}
|
|
default: r = 0.0; break;
|
|
}
|
|
vals[(*vtop)++] = r;
|
|
}
|
|
|
|
int main(void) {
|
|
// 读取整行表达式
|
|
char *line = NULL;
|
|
size_t cap = 0;
|
|
{
|
|
size_t bufcap = 1024; // 表达式长度 ≤ 30,这里足够
|
|
line = (char*)malloc(bufcap);
|
|
if (!line) return 1;
|
|
if (!fgets(line, (int)bufcap, stdin)) return 0;
|
|
size_t len = strlen(line);
|
|
while (len && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0';
|
|
cap = len + 1;
|
|
}
|
|
|
|
size_t L = strlen(line);
|
|
// 栈容量按输入长度分配
|
|
long double *vals = (long double*)malloc((L + 1) * sizeof(long double));
|
|
char *ops = (char*)malloc(L + 1);
|
|
if (!vals || !ops) return 1;
|
|
int vtop = 0, otop = 0;
|
|
|
|
int expect_unary = 1; // 是否期待一元运算符(开头或在'('或二元运算符之后)
|
|
|
|
for (size_t i = 0; i < L;) {
|
|
char c = line[i];
|
|
if (isspace((unsigned char)c)) { ++i; continue; }
|
|
if (c >= '0' && c <= '9') {
|
|
// 解析数字(整数)
|
|
long long x = 0;
|
|
while (i < L && line[i] >= '0' && line[i] <= '9') {
|
|
x = x * 10 + (line[i] - '0');
|
|
++i;
|
|
}
|
|
vals[vtop++] = (long double)x;
|
|
expect_unary = 0;
|
|
} else if (c == '(') {
|
|
ops[otop++] = c;
|
|
++i;
|
|
expect_unary = 1;
|
|
} else if (c == ')') {
|
|
while (otop > 0 && ops[otop - 1] != '(') {
|
|
apply_top(vals, &vtop, ops, &otop);
|
|
}
|
|
if (otop > 0 && ops[otop - 1] == '(') --otop; // 弹出左括号
|
|
++i;
|
|
expect_unary = 0;
|
|
} else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^') {
|
|
// 处理一元 ±
|
|
if (expect_unary && (c == '+' || c == '-')) {
|
|
if (c == '-') {
|
|
// 一元负号入栈(最高优先级)
|
|
ops[otop++] = '~';
|
|
}
|
|
// 一元 '+' 不产生效果,直接跳过
|
|
++i;
|
|
expect_unary = 1; // 仍可能继续接 '(' 或 数字
|
|
continue;
|
|
}
|
|
|
|
// 处理二元运算符的结合与优先级
|
|
int p = prec(c);
|
|
int right_assoc = (c == '^');
|
|
while (otop > 0 && ops[otop - 1] != '(') {
|
|
int pt = prec(ops[otop - 1]);
|
|
if ((right_assoc && pt > p) || (!right_assoc && pt >= p)) {
|
|
apply_top(vals, &vtop, ops, &otop);
|
|
} else break;
|
|
}
|
|
ops[otop++] = c;
|
|
++i;
|
|
expect_unary = 1;
|
|
} else {
|
|
// 其他字符(若存在):跳过
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// 清空剩余操作符
|
|
while (otop > 0) {
|
|
apply_top(vals, &vtop, ops, &otop);
|
|
}
|
|
|
|
// 四舍五入输出整数
|
|
if (vtop > 0) {
|
|
long double res = vals[vtop - 1];
|
|
long long rounded = roundll(res);
|
|
printf("%lld\n", rounded);
|
|
}
|
|
|
|
free(vals);
|
|
free(ops);
|
|
free(line);
|
|
return 0;
|
|
} |