✨ Support calculate ^0.5
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// === 在 abstract class Expr 中添加声明 ===
|
||||
import 'dart:math' show sqrt, cos, sin, tan;
|
||||
import 'dart:math' show sqrt, cos, sin, tan, pow;
|
||||
|
||||
abstract class Expr {
|
||||
Expr simplify();
|
||||
@@ -488,7 +488,7 @@ class SqrtExpr extends Expr {
|
||||
SqrtExpr(inner.substitute(varName, value));
|
||||
|
||||
@override
|
||||
String toString() => "sqrt($inner)";
|
||||
String toString() => "\\sqrt{${inner.toString()}}";
|
||||
}
|
||||
|
||||
// === CosExpr ===
|
||||
@@ -584,6 +584,90 @@ class TanExpr extends Expr {
|
||||
String toString() => "tan($inner)";
|
||||
}
|
||||
|
||||
// === PowExpr ===
|
||||
class PowExpr extends Expr {
|
||||
final Expr left, right;
|
||||
PowExpr(this.left, this.right);
|
||||
|
||||
@override
|
||||
Expr simplify() {
|
||||
var l = left.simplify();
|
||||
var r = right.simplify();
|
||||
|
||||
// x^0 = 1
|
||||
if (r is IntExpr && r.value == 0) return IntExpr(1);
|
||||
// x^1 = x
|
||||
if (r is IntExpr && r.value == 1) return l;
|
||||
// 1^x = 1
|
||||
if (l is IntExpr && l.value == 1) return IntExpr(1);
|
||||
// 0^x = 0 (for x != 0)
|
||||
if (l is IntExpr && l.value == 0 && !(r is IntExpr && r.value == 0)) {
|
||||
return IntExpr(0);
|
||||
}
|
||||
|
||||
return PowExpr(l, r);
|
||||
}
|
||||
|
||||
@override
|
||||
Expr evaluate() {
|
||||
var l = left.evaluate();
|
||||
var r = right.evaluate();
|
||||
|
||||
// x^0 = 1
|
||||
if (r is IntExpr && r.value == 0) return IntExpr(1);
|
||||
// x^1 = x
|
||||
if (r is IntExpr && r.value == 1) return l;
|
||||
// 1^x = 1
|
||||
if (l is IntExpr && l.value == 1) return IntExpr(1);
|
||||
// 0^x = 0 (for x != 0)
|
||||
if (l is IntExpr && l.value == 0 && !(r is IntExpr && r.value == 0))
|
||||
return IntExpr(0);
|
||||
|
||||
// If both are numbers, compute
|
||||
if (l is IntExpr && r is IntExpr) {
|
||||
return DoubleExpr(pow(l.value.toDouble(), r.value.toDouble()).toDouble());
|
||||
}
|
||||
if (l is DoubleExpr && r is IntExpr) {
|
||||
return DoubleExpr(pow(l.value, r.value.toDouble()).toDouble());
|
||||
}
|
||||
if (l is IntExpr && r is DoubleExpr) {
|
||||
return DoubleExpr(pow(l.value.toDouble(), r.value).toDouble());
|
||||
}
|
||||
if (l is DoubleExpr && r is DoubleExpr) {
|
||||
return DoubleExpr(pow(l.value, r.value).toDouble());
|
||||
}
|
||||
|
||||
return PowExpr(l, r);
|
||||
}
|
||||
|
||||
@override
|
||||
Expr substitute(String varName, Expr value) => PowExpr(
|
||||
left.substitute(varName, value),
|
||||
right.substitute(varName, value),
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
String leftStr = left.toString();
|
||||
String rightStr = right.toString();
|
||||
|
||||
// Remove outer parentheses
|
||||
if (leftStr.startsWith('(') && leftStr.endsWith(')')) {
|
||||
leftStr = leftStr.substring(1, leftStr.length - 1);
|
||||
}
|
||||
if (rightStr.startsWith('(') && rightStr.endsWith(')')) {
|
||||
rightStr = rightStr.substring(1, rightStr.length - 1);
|
||||
}
|
||||
|
||||
// Add parentheses around base if it's a complex expression
|
||||
bool needsParens =
|
||||
!(left is VarExpr || left is IntExpr || left is DoubleExpr);
|
||||
String base = needsParens ? '($leftStr)' : leftStr;
|
||||
|
||||
return '$base^{$rightStr}';
|
||||
}
|
||||
}
|
||||
|
||||
// === 辅助:识别 a * sqrt(X) 形式 ===
|
||||
class _SqrtTerm {
|
||||
final int coef;
|
||||
|
@@ -33,12 +33,12 @@ class Parser {
|
||||
}
|
||||
|
||||
Expr parseMul() {
|
||||
var expr = parseAtom();
|
||||
var expr = parsePow();
|
||||
skipSpaces();
|
||||
while (!isEnd && (current == '*' || current == '/')) {
|
||||
var op = current;
|
||||
eat();
|
||||
var right = parseAtom();
|
||||
var right = parsePow();
|
||||
if (op == '*') {
|
||||
expr = MulExpr(expr, right);
|
||||
} else {
|
||||
@@ -49,6 +49,17 @@ class Parser {
|
||||
return expr;
|
||||
}
|
||||
|
||||
Expr parsePow() {
|
||||
var expr = parseAtom();
|
||||
skipSpaces();
|
||||
if (!isEnd && current == '^') {
|
||||
eat();
|
||||
var right = parsePow(); // right associative
|
||||
return PowExpr(expr, right);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
Expr parseAtom() {
|
||||
skipSpaces();
|
||||
if (current == '(') {
|
||||
@@ -106,13 +117,20 @@ class Parser {
|
||||
return VarExpr(varName);
|
||||
}
|
||||
|
||||
// 解析整数
|
||||
// 解析数字 (整数或小数)
|
||||
var buf = '';
|
||||
while (!isEnd && RegExp(r'\d').hasMatch(current)) {
|
||||
bool hasDot = false;
|
||||
while (!isEnd &&
|
||||
(RegExp(r'\d').hasMatch(current) || (!hasDot && current == '.'))) {
|
||||
if (current == '.') hasDot = true;
|
||||
buf += current;
|
||||
eat();
|
||||
}
|
||||
if (buf.isEmpty) throw Exception("无法解析: $current");
|
||||
return IntExpr(int.parse(buf));
|
||||
if (hasDot) {
|
||||
return DoubleExpr(double.parse(buf));
|
||||
} else {
|
||||
return IntExpr(int.parse(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,12 +52,17 @@ class SolverService {
|
||||
/// 1. 求解简单表达式
|
||||
CalculationResult _solveSimpleExpression(String input) {
|
||||
final steps = <CalculationStep>[];
|
||||
// Parse the input to get LaTeX-formatted version
|
||||
final parser = Parser(input);
|
||||
final parsedExpr = parser.parse();
|
||||
final latexInput = parsedExpr.toString().replaceAll('*', '\\cdot');
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
stepNumber: 1,
|
||||
title: '表达式求值',
|
||||
explanation: '这是一个标准的数学表达式,我们将直接计算其结果。',
|
||||
formula: '\$\$$input\$\$',
|
||||
formula: '\$\$$latexInput\$\$',
|
||||
),
|
||||
);
|
||||
|
||||
@@ -113,12 +118,17 @@ class SolverService {
|
||||
/// 2. 求解一元一次方程
|
||||
CalculationResult _solveLinearEquation(String input) {
|
||||
final steps = <CalculationStep>[];
|
||||
// Parse the input to get LaTeX-formatted version
|
||||
final parser = Parser(input);
|
||||
final parsedExpr = parser.parse();
|
||||
final latexInput = parsedExpr.toString().replaceAll('*', '\\cdot');
|
||||
|
||||
steps.add(
|
||||
CalculationStep(
|
||||
stepNumber: 0,
|
||||
title: '原方程',
|
||||
explanation: '这是一元一次方程。',
|
||||
formula: '\$\$$input\$\$',
|
||||
formula: '\$\$$latexInput\$\$',
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1262,8 +1272,7 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
|
||||
|
||||
/// 格式化原始方程,保持符号形式
|
||||
String _formatOriginalEquation(String input) {
|
||||
// Simply return the original equation with proper LaTeX formatting
|
||||
// This avoids complex parsing issues and preserves the original symbolic form
|
||||
// Parse the equation and convert to LaTeX
|
||||
String result = input.replaceAll(' ', '');
|
||||
|
||||
// 确保方程格式正确
|
||||
@@ -1271,9 +1280,31 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
|
||||
result = '$result=0';
|
||||
}
|
||||
|
||||
// Replace sqrt with LaTeX format
|
||||
result = result.replaceAll('sqrt(', '\\sqrt{');
|
||||
result = result.replaceAll(')', '}');
|
||||
final parts = result.split('=');
|
||||
if (parts.length == 2) {
|
||||
try {
|
||||
final leftParser = Parser(parts[0]);
|
||||
final leftExpr = leftParser.parse();
|
||||
final rightParser = Parser(parts[1]);
|
||||
final rightExpr = rightParser.parse();
|
||||
result =
|
||||
'${leftExpr.toString().replaceAll('*', '\\cdot')}=${rightExpr.toString().replaceAll('*', '\\cdot')}';
|
||||
} catch (e) {
|
||||
// Fallback to original if parsing fails
|
||||
result = result.replaceAll('sqrt(', '\\sqrt{');
|
||||
result = result.replaceAll(')', '}');
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
final parser = Parser(result.split('=')[0]);
|
||||
final expr = parser.parse();
|
||||
result = '${expr.toString().replaceAll('*', '\\cdot')}=0';
|
||||
} catch (e) {
|
||||
// Fallback
|
||||
result = result.replaceAll('sqrt(', '\\sqrt{');
|
||||
result = result.replaceAll(')', '}');
|
||||
}
|
||||
}
|
||||
|
||||
return '\$\$$result\$\$';
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ void main() {
|
||||
|
||||
test('非完全平方数', () {
|
||||
var expr = Parser("sqrt(8)").parse();
|
||||
expect(expr.simplify().toString().replaceAll(' ', ''), "(2*sqrt(2))");
|
||||
expect(expr.simplify().toString().replaceAll(' ', ''), "(2*\\sqrt{2})");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ void main() {
|
||||
var expr = Parser("sqrt(8)/4 + 1/2").parse();
|
||||
expect(
|
||||
expr.evaluate().toString().replaceAll(' ', ''),
|
||||
"((sqrt(2)/2)+1/2)",
|
||||
"((\\sqrt{2}/2)+1/2)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user