AI解方程计算器(1.0测试版)
2026-07-31 10:38:02
发布于:浙江
#include <iostream>
#include <stack>
#include <string>
#include <sstream>
#include <cctype>
#include <stdexcept>
#include <cmath>
#include <algorithm>
using namespace std;
// ============================================================
// 第一部分:通用工具函数
// ============================================================
// 跳过空格
inline void skip_space(const string& s, size_t& pos) {
while (pos < s.size() && isspace(s[pos])) ++pos;
}
// 运算符优先级
int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
if (op == '^') return 3; // 幂运算,留作扩展
return 0;
}
// 是否是二元运算符
bool is_binary_op(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
// ============================================================
// 第二部分:中缀表达式求值(支持隐式乘法)
// ============================================================
// 在表达式中插入显式乘号,例如:
// 2x -> 2*x, 3(x+1) -> 3*(x+1), (x+1)(x+2) -> (x+1)*(x+2)
// x(2) -> x*(2) 等
string insert_implicit_mul(const string& expr) {
string result;
for (size_t i = 0; i < expr.size(); ++i) {
char c = expr[i];
if (c == ' ') continue; // 空格稍后统一处理,先跳过
// 当满足以下情况之一时,需要插入 '*':
// 1) 数字后跟字母 (如 2x)
// 2) 数字后跟 '(' (如 2(x+1))
// 3) ')'后跟数字 (如 (x+1)2——少见但支持)
// 4) ')'后跟字母 (如 (x+1)x)
// 5) ')'后跟 '(' (如 (x+1)(x+2))
// 6) 字母后跟数字 (如 x2 即 x*2)
// 7) 字母后跟 '(' (如 x(2))
// 8) 字母后跟字母 (如 xy → x*y ——但一元一次只有x,一般不会,保留兼容)
if (!result.empty()) {
char prev = result.back();
// 忽略前一个字符是运算符、左括号、等号的情况
bool prev_is_num = (prev >= '0' && prev <= '9') || prev == '.';
bool prev_is_paren = (prev == ')');
bool prev_is_letter = (prev == 'x' || prev == 'X');
bool cur_is_letter = (c == 'x' || c == 'X');
bool cur_is_num = (c >= '0' && c <= '9') || c == '.';
bool cur_is_paren = (c == '(');
bool need_mul = false;
// 数字/')'/字母 后跟 字母/'('/数字
if ((prev_is_num || prev_is_paren || prev_is_letter) &&
(cur_is_letter || cur_is_paren || cur_is_num)) {
// 但如果前一个是数字、后一个是数字,中间不加(如"10.5"是同一个数)
if (!(prev_is_num && cur_is_num)) {
need_mul = true;
}
}
if (prev == ')' && cur_is_letter) need_mul = true;
if (prev == ')' && cur_is_paren) need_mul = true;
if (prev_is_letter && cur_is_num) need_mul = true;
if (prev_is_letter && cur_is_paren) need_mul = true;
if (prev_is_num && cur_is_letter) need_mul = true;
if (prev_is_num && cur_is_paren) need_mul = true;
if (need_mul) result += '*';
}
result += c;
}
return result;
}
// 对表达式做预处理:去空格 + 插入隐式乘号
string preprocess(const string& expr) {
string cleaned;
for (char c : expr) {
if (!isspace(c)) cleaned += c;
}
return insert_implicit_mul(cleaned);
}
// 解析数字(含小数)
double parse_number(const string& expr, size_t& pos) {
size_t start = pos;
bool has_dot = false;
while (pos < expr.size() &&
(isdigit(expr[pos]) || (!has_dot && expr[pos] == '.'))) {
if (expr[pos] == '.') has_dot = true;
pos++;
}
string num_str = expr.substr(start, pos - start);
if (num_str.empty() || num_str == ".")
throw invalid_argument("数字格式错误");
return stod(num_str);
}
// 应用二元运算
double apply_op(double a, double b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (fabs(b) < 1e-12) throw runtime_error("除数不能为零");
return a / b;
default:
throw runtime_error("未知运算符");
}
}
// 中缀表达式求值(在预处理后的表达式中,x 被视为变量名——求值时若遇到 x 则抛出异常)
// 若 need_x_value 为 true,遇到 'x' 返回给定的 x_val
double evaluate_impl(const string& expr, size_t& pos, double x_val,
bool allow_x) {
stack<double> values;
stack<char> ops;
size_t n = expr.size();
auto apply_top = [&]() {
if (ops.empty()) throw runtime_error("运算符栈空");
if (values.size() < 2) throw runtime_error("操作数不足");
char op = ops.top(); ops.pop();
double b = values.top(); values.pop();
double a = values.top(); values.pop();
values.push(apply_op(a, b, op));
};
while (pos < n) {
char c = expr[pos];
if (c == ' ') { pos++; continue; }
// 数字
if (isdigit(c) || c == '.') {
values.push(parse_number(expr, pos));
continue;
}
// x 变量
if (c == 'x' || c == 'X') {
if (allow_x) {
values.push(x_val);
} else {
throw runtime_error("表达式中含未知变量 x,请使用方程求解功能");
}
pos++;
continue;
}
// 左括号
if (c == '(') {
ops.push('(');
pos++;
continue;
}
// 右括号
if (c == ')') {
while (!ops.empty() && ops.top() != '(') apply_top();
if (ops.empty()) throw runtime_error("括号不匹配");
ops.pop(); // 弹出 '('
pos++;
continue;
}
// 等号(用于方程)
if (c == '=') {
// 遇到等号,表示这是方程,需要特殊处理
throw runtime_error("遇到等号: 方程需要调用解方程功能");
}
// 运算符
if (is_binary_op(c)) {
// 处理一元负号
if (c == '-' && (pos == 0 || expr[pos-1] == '(' ||
is_binary_op(expr[pos-1]))) {
pos++;
skip_space(expr, pos);
if (pos >= n || !(isdigit(expr[pos]) || expr[pos] == '.' ||
expr[pos] == 'x' || expr[pos] == 'X' ||
expr[pos] == '('))
throw runtime_error("负号后缺少操作数");
values.push(-1.0);
ops.push('*');
continue;
}
// 处理优先级
while (!ops.empty() && ops.top() != '(' &&
precedence(ops.top()) >= precedence(c)) {
apply_top();
}
ops.push(c);
pos++;
continue;
}
throw runtime_error(string("非法字符 '") + c + "'");
}
while (!ops.empty()) apply_top();
if (values.size() != 1)
throw runtime_error("表达式格式错误");
return values.top();
}
// 对外求值接口:完全求值(不含 x 或 指定 x 值)
double evaluate(const string& expr, double x_val = 0.0, bool allow_x = false) {
string prep = preprocess(expr);
size_t pos = 0;
return evaluate_impl(prep, pos, x_val, allow_x);
}
// ============================================================
// 第三部分:解一元一次方程(支持隐式乘法)
// ============================================================
// 将方程两边分别表示为关于 x 的表达式,通过二分法求根
// 方程形式: 左边 = 右边,如 "2x+3=7" 或 "3(x+1)=2x-5"
double solve_equation(const string& equation_str) {
// 查找等号位置
string eq = equation_str;
eq.erase(remove_if(eq.begin(), eq.end(), ::isspace), eq.end());
size_t eq_pos = eq.find('=');
if (eq_pos == string::npos)
throw invalid_argument("方程中缺少等号 '='");
string left_expr = eq.substr(0, eq_pos);
string right_expr = eq.substr(eq_pos + 1);
// 都预处理(插入隐式乘号)
string left_prep = preprocess(left_expr);
string right_prep = preprocess(right_expr);
// 利用二分法求解 f(x) = left - right = 0
// 先估计大致范围,从 [-1e6, 1e6] 开始搜索
auto f = [&](double x) -> double {
size_t lpos = 0, rpos = 0;
double lval = evaluate_impl(left_prep, lpos, x, true);
double rval = evaluate_impl(right_prep, rpos, x, true);
return lval - rval;
};
// 先在较大范围内找异号区间
double lo = -1e6, hi = 1e6;
double flo = f(lo), fhi = f(hi);
// 如果边界刚好是根
if (fabs(flo) < 1e-12) return lo;
if (fabs(fhi) < 1e-12) return hi;
// 扩大搜索范围(处理系数很大的情况)
for (int scale = 1; scale <= 100; ++scale) {
lo = -1e6 * scale;
hi = 1e6 * scale;
flo = f(lo);
fhi = f(hi);
if (flo * fhi < 0) break;
if (scale == 100)
throw runtime_error("无法确定根的范围(可能是恒等式或无解?)");
}
// 二分法
for (int iter = 0; iter < 200; ++iter) {
double mid = (lo + hi) / 2.0;
double fmid = f(mid);
if (fabs(fmid) < 1e-12) return mid;
if (flo * fmid < 0) {
hi = mid;
fhi = fmid;
} else {
lo = mid;
flo = fmid;
}
}
return (lo + hi) / 2.0;
}
// ============================================================
// 第四部分:主程序(交互式菜单)
// ============================================================
void print_menu() {
cout << "\n==========================================" << endl;
cout << " 高级数学计算器 (C++11)" << endl;
cout << "==========================================" << endl;
cout << "模式选择:" << endl;
cout << " 1 → 计算表达式(中缀表达式求值)" << endl;
cout << " 2 → 解一元一次方程" << endl;
cout << " q → 退出" << endl;
cout << "------------------------------------------" << endl;
cout << "表达式支持的语法:" << endl;
cout << " + - * / ( ) | 隐式乘法: 2x, 3(x+1)" << endl;
cout << " 小数、负数 | 方程支持: 2x+3=7" << endl;
cout << "==========================================" << endl;
}
int main() {
print_menu();
string input;
while (true) {
cout << "\n>> ";
getline(cin, input);
if (input.empty()) continue;
// 处理退出
string cmd = input;
transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);
if (cmd == "q" || cmd == "quit" || cmd == "exit" || cmd == "退出") {
cout << "感谢使用,再见!" << endl;
break;
}
// 切换模式
if (cmd == "1" || cmd == "expr" || cmd == "计算") {
cout << "【表达式求值模式】" << endl;
cout << "请输入表达式: ";
getline(cin, input);
if (input.empty()) continue;
try {
// 先判断是否可能是一元一次方程(等号)
string test = input;
test.erase(remove_if(test.begin(), test.end(), ::isspace),
test.end());
if (test.find('=') != string::npos) {
cout << "检测到等号,建议切换到解方程模式(2)" << endl;
continue;
}
double result = evaluate(input, 0, false);
// 整数化输出
if (fabs(result - round(result)) < 1e-12)
cout << "结果: " << (long long)round(result) << endl;
else
cout << "结果: " << result << endl;
} catch (const exception& e) {
cout << "错误: " << e.what() << endl;
}
continue;
}
if (cmd == "2" || cmd == "solve" || cmd == "方程" || cmd == "解方程") {
cout << "【解方程模式】" << endl;
cout << "请输入一元一次方程 (如 2x+3=7 或 3(x+1)=2x-5): ";
getline(cin, input);
if (input.empty()) continue;
try {
double solution = solve_equation(input);
// 美化输出
string sol_str;
if (fabs(solution - round(solution)) < 1e-12)
sol_str = to_string((long long)round(solution));
else
sol_str = to_string(solution);
// 去掉尾部多余0
if (sol_str.find('.') != string::npos) {
sol_str.erase(sol_str.find_last_not_of('0') + 1, string::npos);
if (sol_str.back() == '.') sol_str.pop_back();
}
cout << "方程的解: x = " << sol_str << endl;
} catch (const exception& e) {
cout << "错误: " << e.what() << endl;
}
continue;
}
// 默认:智能检测
try {
string test = input;
test.erase(remove_if(test.begin(), test.end(), ::isspace),
test.end());
if (test.find('=') != string::npos) {
// 有等号 → 解方程
double solution = solve_equation(input);
string sol_str;
if (fabs(solution - round(solution)) < 1e-12)
sol_str = to_string((long long)round(solution));
else
sol_str = to_string(solution);
if (sol_str.find('.') != string::npos) {
sol_str.erase(sol_str.find_last_not_of('0') + 1, string::npos);
if (sol_str.back() == '.') sol_str.pop_back();
}
cout << "方程的解: x = " << sol_str << endl;
} else {
// 无等号 → 表达式求值
double result = evaluate(input, 0, false);
if (fabs(result - round(result)) < 1e-12)
cout << "结果: " << (long long)round(result) << endl;
else
cout << "结果: " << result << endl;
}
} catch (const exception& e) {
cout << "错误: " << e.what() << endl;
}
}
return 0;
}
要是想要其他功能,可以告诉我
这里空空如也

















有帮助,赞一个