Compare commits

..

3 Commits

Author SHA1 Message Date
1455c0b98c Support multi variables 2025-09-16 22:47:48 +08:00
1b80702bbe 🗑️ Clean up code 2025-09-16 22:17:57 +08:00
ac101a2f0e 💄 Optimize proity of solving ways 2025-09-16 20:05:40 +08:00

View File

@@ -24,15 +24,101 @@ class SolverService {
return formatted;
}
/// 尝试对二次方程进行因式分解
String? _tryFactorQuadratic(double a, double b, double c) {
if (a != a.round() || b != b.round() || c != c.round()) return null;
int aa = a.round(), bb = b.round(), cc = c.round();
if (aa == 0) return null; // 不是二次方程
// 简单情况:如果 a=1尝试简单的因式分解
if (aa == 1) {
// 寻找两个因式 (x + m)(x + n) = x^2 + (m+n)x + mn
// 需要满足 m+n = -b, mn = c
for (int m = -100; m <= 100; m++) {
for (int n = -100; n <= 100; n++) {
if (m + n == -bb && m * n == cc) {
String factor1 = _formatFactorTerm(1, -m, 'x');
String factor2 = _formatFactorTerm(1, -n, 'x');
return '($factor1)($factor2)';
}
}
}
}
// 简单情况:如果 a=-1尝试简单的因式分解
if (aa == -1) {
// 寻找两个因式 -(x + m)(x + n) = -x^2 - (m+n)x - mn
// 需要满足 m+n = b, mn = -c
for (int m = -100; m <= 100; m++) {
for (int n = -100; n <= 100; n++) {
if (m + n == bb && m * n == -cc) {
String factor1 = _formatFactorTerm(1, m);
String factor2 = _formatFactorTerm(1, n);
return '-($factor1)($factor2)';
}
}
}
}
// 对于更复杂的情况,暂时不进行因式分解
return null;
}
/// 格式化因式中的项
String _formatFactorTerm(int coeff, int constTerm, [String variable = 'x']) {
String result = '';
if (coeff != 0) {
if (coeff == 1)
result += variable;
else if (coeff == -1)
result += '-$variable';
else
result += '${coeff}$variable';
}
if (constTerm != 0) {
if (result.isNotEmpty) {
if (constTerm > 0)
result += ' + $constTerm';
else
result += ' - ${-constTerm}';
} else {
result += constTerm.toString();
}
}
if (result.isEmpty) result = '0';
return result;
}
/// 检测方程中的变量
Set<String> _detectVariables(String input) {
final variablePattern = RegExp(r'\b([a-zA-Z])\b');
final matches = variablePattern.allMatches(input);
return matches.map((match) => match.group(1)!).toSet();
}
/// 主入口方法,识别并分发任务
CalculationResult solve(String input) {
// 预处理输入字符串
final cleanInput = input.replaceAll(' ', '').toLowerCase();
// 对包含x的方程进行预处理展开表达式
// 检测方程中的变量
final variables = _detectVariables(cleanInput);
if (variables.isEmpty) {
// 如果没有变量,当作简单表达式处理
try {
return _solveSimpleExpression(input);
} catch (e) {
throw Exception('无法识别的格式。请检查您的方程或表达式。');
}
}
// 获取主变量(第一个检测到的变量)
final mainVariable = variables.first;
// 对包含变量的方程进行预处理,展开表达式
String processedInput = cleanInput;
if (processedInput.contains('x') && processedInput.contains('(')) {
processedInput = _expandExpressions(processedInput);
if (processedInput.contains(mainVariable) && processedInput.contains('(')) {
processedInput = _expandExpressions(processedInput, mainVariable);
}
// 0. 检查是否是 (expr)^n = constant 的形式(任意次幂)
@@ -48,13 +134,19 @@ class SolverService {
final rightValue = double.tryParse(rightStr);
if (rightValue != null) {
return _solveGeneralPowerEquation(exprStr, n, rightValue, cleanInput);
return _solveGeneralPowerEquation(
exprStr,
n,
rightValue,
cleanInput,
mainVariable,
);
}
}
// 0.5. 检查是否是 a(expr)^2 = b 的形式(向后兼容)
final squareEqMatch = RegExp(
r'^(\d*\.?\d*)\(([^)]+)\)\^2\s*=\s*(.+)$',
r'^(\d*\.?\d*)?\(([^)]+)\)\^2\s*=\s*(.+)$',
).firstMatch(cleanInput);
if (squareEqMatch != null) {
final coeffStr = squareEqMatch.group(1)!;
@@ -67,14 +159,16 @@ class SolverService {
// 解析右边
double right = double.parse(rightStr);
// 解析 expr 为 x ± h
final exprMatch = RegExp(r'x\s*([+-]\s*\d*\.?\d*)?').firstMatch(exprStr);
// 解析 expr 为 variable ± h
final exprMatch = RegExp(
r'$mainVariable\s*([+-]\s*\d*\.?\d*)?',
).firstMatch(exprStr);
if (exprMatch != null) {
final hStr = exprMatch.group(1) ?? '';
double constant = hStr.isEmpty
? 0.0
: double.parse(hStr.replaceAll(' ', ''));
double h = -constant; // For (x - h)^2, h is the center
double h = -constant; // For (var - h)^2, h is the center
// 使用有理数计算
final coeffRat = _rationalFromDouble(coeff);
@@ -108,44 +202,49 @@ class SolverService {
title: '开方',
explanation: '对方程两边同时开平方。',
formula:
'\$\$x ${h >= 0 ? '+' : ''}$h = \\pm \\sqrt{\\frac{${innerRat.numerator}}{${innerRat.denominator}}}\$\$',
'\$\$${mainVariable} ${h >= 0 ? '+' : ''}$h = \\pm \\sqrt{\\frac{${innerRat.numerator}}{${innerRat.denominator}}}\$\$',
),
CalculationStep(
stepNumber: 4,
title: '解出 x',
explanation: '分别取正负号,解出 x 的值。',
formula: '\$\$x_1 = $x1Str, \\quad x_2 = $x2Str\$\$',
title: '解出 ${mainVariable}',
explanation: '分别取正负号,解出 ${mainVariable} 的值。',
formula:
'\$\$${mainVariable}_1 = $x1Str, \\quad ${mainVariable}_2 = $x2Str\$\$',
),
],
finalAnswer: '\$\$x_1 = $x1Str, \\quad x_2 = $x2Str\$\$',
finalAnswer:
'\$\$${mainVariable}_1 = $x1Str, \\quad ${mainVariable}_2 = $x2Str\$\$',
);
}
}
}
// 1. 检查是否为元一次方程组 (格式: ...;...)
if (processedInput.contains(';') &&
processedInput.contains('x') &&
processedInput.contains('y')) {
return _solveSystemOfLinearEquations(processedInput);
// 1. 检查是否为元一次方程组 (格式: ...;...)
if (processedInput.contains(';') && variables.length > 1) {
return _solveSystemOfLinearEquations(processedInput, variables);
}
// 2. 检查是否为一元二次方程 (包含 x^2 或 x²)
if (processedInput.contains('x^2') || processedInput.contains('')) {
return _solveQuadraticEquation(processedInput.replaceAll('', 'x^2'));
// 2. 检查是否为一元二次方程 (包含 variable^2 或 variable²)
if (processedInput.contains('${mainVariable}^2') ||
processedInput.contains('${mainVariable}²')) {
return _solveQuadraticEquation(
processedInput.replaceAll('${mainVariable}²', '${mainVariable}^2'),
mainVariable,
);
}
// 3. 检查是否为幂次方程 (x^n = a 的形式)
if (processedInput.contains('x^') && processedInput.contains('=')) {
return _solvePowerEquation(processedInput);
// 3. 检查是否为幂次方程 (variable^n = a 的形式)
if (processedInput.contains('${mainVariable}^') &&
processedInput.contains('=')) {
return _solvePowerEquation(processedInput, mainVariable);
}
// 4. 检查是否为一元一次方程 (包含 x 但不包含 y 或 x^2)
if (processedInput.contains('x') && !processedInput.contains('y')) {
return _solveLinearEquation(processedInput);
// 4. 检查是否为一元一次方程 (包含主变量)
if (processedInput.contains(mainVariable)) {
return _solveLinearEquation(processedInput, mainVariable);
}
// 4. 如果都不是,则作为简单表达式计算
// 如果都不是,则作为简单表达式计算
try {
return _solveSimpleExpression(input); // 使用原始输入以保留运算符
} catch (e) {
@@ -222,7 +321,10 @@ class SolverService {
}
/// 2. 求解一元一次方程
CalculationResult _solveLinearEquation(String input) {
CalculationResult _solveLinearEquation(
String input, [
String variable = 'x',
]) {
final steps = <CalculationStep>[];
// Parse the input to get LaTeX-formatted version
final parser = Parser(input);
@@ -238,7 +340,7 @@ class SolverService {
),
);
final parts = _parseLinearEquation(input);
final parts = _parseLinearEquation(input, variable);
final a = parts.a, b = parts.b, c = parts.c, d = parts.d;
final newA = _rationalFromDouble(a) - _rationalFromDouble(c);
@@ -248,9 +350,9 @@ class SolverService {
CalculationStep(
stepNumber: 1,
title: '移项',
explanation: '将所有含 x 的项移到等式左边,常数项移到右边。',
explanation: '将所有含 ${variable} 的项移到等式左边,常数项移到右边。',
formula:
'\$\$${a}x ${c >= 0 ? '-' : '+'} ${c.abs()}x = $d ${b >= 0 ? '-' : '+'} ${b.abs()}\$\$',
'\$\$${a}${variable} ${c >= 0 ? '-' : '+'} ${c.abs()}${variable} = $d ${b >= 0 ? '-' : '+'} ${b.abs()}\$\$',
),
);
@@ -260,7 +362,7 @@ class SolverService {
title: '合并同类项',
explanation: '合并等式两边的项。',
formula:
'\$\$${_formatNumber(newA.toDouble())}x = ${_formatNumber(newD.toDouble())}\$\$',
'\$\$${_formatNumber(newA.toDouble())}${variable} = ${_formatNumber(newD.toDouble())}\$\$',
),
);
@@ -275,17 +377,23 @@ class SolverService {
steps.add(
CalculationStep(
stepNumber: 3,
title: '求解 x',
explanation: '两边同时除以 x 的系数 ($newA)。',
formula: '\$\$x = \\frac{$newD}{$newA}\$\$',
title: '求解 ${variable}',
explanation: '两边同时除以 ${variable} 的系数 ($newA)。',
formula: '\$\$${variable} = \\frac{$newD}{$newA}\$\$',
),
);
return CalculationResult(steps: steps, finalAnswer: '\$\$x = $x\$\$');
return CalculationResult(
steps: steps,
finalAnswer: '\$\$${variable} = $x\$\$',
);
}
/// 3. 求解一元二次方程 (升级版)
CalculationResult _solveQuadraticEquation(String input) {
CalculationResult _solveQuadraticEquation(
String input, [
String variable = 'x',
]) {
final steps = <CalculationStep>[];
final eqParts = input.split('=');
@@ -311,8 +419,8 @@ class SolverService {
// );
// Also get numeric values for calculations
final leftCoeffs = _parsePolynomial(eqParts[0]);
final rightCoeffs = _parsePolynomial(eqParts[1]);
final leftCoeffs = _parsePolynomial(eqParts[0], variable);
final rightCoeffs = _parsePolynomial(eqParts[1], variable);
final a = (leftCoeffs[2] ?? 0) - (rightCoeffs[2] ?? 0);
final b = (leftCoeffs[1] ?? 0) - (rightCoeffs[1] ?? 0);
final c = (leftCoeffs[0] ?? 0) - (rightCoeffs[0] ?? 0);
@@ -330,14 +438,63 @@ class SolverService {
),
);
steps.add(
CalculationStep(
stepNumber: 2,
title: '选择解法',
explanation: '我们选择使用配方法。',
formula: r'配方法:$x^2 + \frac{b}{a}x + \frac{c}{a} = 0$',
),
);
final factored = _tryFactorQuadratic(a, b, c);
if (factored != null) {
steps.add(
CalculationStep(
stepNumber: 2,
title: '选择解法',
explanation: '我们选择使用因式分解法。',
formula: '\$\$ax^2 + bx + c = 0\$\$',
),
);
steps.add(
CalculationStep(
stepNumber: 3,
title: '因式分解',
explanation: '将二次方程分解为两个一次因式的乘积。',
formula: '\$\$$factored = 0\$\$',
),
);
// Parse the factored form to find the roots
final roots = _calculateRootsFromFactoredForm(factored);
steps.add(
CalculationStep(
stepNumber: 4,
title: '解出 x',
explanation: '分别令每个因式为零,解出 x 的值。',
formula: roots.formula,
),
);
return CalculationResult(steps: steps, finalAnswer: roots.finalAnswer);
} else {
// 检查系数是否都是整数
bool allIntegers = a == a.round() && b == b.round() && c == c.round();
if (!allIntegers) {
// 使用公式法
steps.add(
CalculationStep(
stepNumber: 2,
title: '选择解法',
explanation: '系数包含非整数,我们选择使用公式法。',
formula: r'公式法:$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$',
),
);
return _solveQuadraticByFormula(a, b, c, steps);
} else {
// 使用配方法
steps.add(
CalculationStep(
stepNumber: 2,
title: '选择解法',
explanation: '我们选择使用配方法。',
formula: r'配方法:$x^2 + \frac{b}{a}x + \frac{c}{a} = 0$',
),
);
}
}
// Step 1: Divide by a if a ≠ 1
String currentEquation;
@@ -465,6 +622,7 @@ class SolverService {
int n,
double rightValue,
String originalInput,
String variable,
) {
final steps = <CalculationStep>[];
@@ -552,8 +710,8 @@ class SolverService {
}
}
/// 3.6. 求解幂次方程 (x^n = a 的形式)
CalculationResult _solvePowerEquation(String input) {
/// 3.6. 求解幂次方程 (variable^n = a 的形式)
CalculationResult _solvePowerEquation(String input, [String variable = 'x']) {
final steps = <CalculationStep>[];
// 解析方程
@@ -563,10 +721,12 @@ class SolverService {
final leftSide = parts[0].trim();
final rightSide = parts[1].trim();
// 检查左边是否为 x^n 的形式
final powerMatch = RegExp(r'^x\^(\d+)$').firstMatch(leftSide);
// 检查左边是否为 variable^n 的形式
final powerMatch = RegExp(
r'^${RegExp.escape(variable)}\^(\d+)$',
).firstMatch(leftSide);
if (powerMatch == null) {
throw Exception("不支持的幂次方程格式。当前支持 x^n = a 的形式。");
throw Exception("不支持的幂次方程格式。当前支持 ${variable}^n = a 的形式。");
}
final n = int.parse(powerMatch.group(1)!);
@@ -597,8 +757,8 @@ class SolverService {
CalculationStep(
stepNumber: 2,
title: '对方程两边同时开 $n 次方',
explanation: '对方程两边同时开 $n 次方以解出 x',
formula: '\$\$x = \\sqrt[$n]{$a}\$\$',
explanation: '对方程两边同时开 $n 次方以解出 ${variable}',
formula: '\$\$${variable} = \\sqrt[$n]{$a}\$\$',
),
);
@@ -626,18 +786,21 @@ class SolverService {
stepNumber: 3,
title: '计算结果',
explanation: '计算开 $n 次方的结果。',
formula: '\$\$x = $resultStr\$\$',
formula: '\$\$${variable} = $resultStr\$\$',
),
);
return CalculationResult(
steps: steps,
finalAnswer: '\$\$x = $resultStr\$\$',
finalAnswer: '\$\$${variable} = $resultStr\$\$',
);
}
/// 4. 求解二元一次方程组
CalculationResult _solveSystemOfLinearEquations(String input) {
CalculationResult _solveSystemOfLinearEquations(
String input, [
Set<String> variables = const {'x', 'y'},
]) {
final steps = <CalculationStep>[];
final equations = input.split(';');
if (equations.length != 2) throw Exception("格式错误, 请用 ';' 分隔两个方程。");
@@ -884,7 +1047,7 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
/// ---- 辅助函数 ----
String _expandExpressions(String input) {
String _expandExpressions(String input, [String variable = 'x']) {
String result = input;
int maxIterations = 10; // Prevent infinite loops
int iterationCount = 0;
@@ -903,7 +1066,7 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
}
final factor = powerMatch.group(2)!;
final coeffs = _parsePolynomial(factor);
final coeffs = _parsePolynomial(factor, variable);
final a = coeffs[1] ?? 0;
final b = coeffs[0] ?? 0;
@@ -926,8 +1089,8 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
final factor2 = factorMulMatch.group(2)!;
log('Expanding: ($factor1) * ($factor2)');
final coeffs1 = _parsePolynomial(factor1);
final coeffs2 = _parsePolynomial(factor2);
final coeffs1 = _parsePolynomial(factor1, variable);
final coeffs2 = _parsePolynomial(factor2, variable);
log('Coeffs1: $coeffs1, Coeffs2: $coeffs2');
final a = coeffs1[1] ?? 0;
@@ -964,8 +1127,8 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
}
// Parse the term (coefficient and x power)
final termCoeffs = _parsePolynomial(termStr);
final factorCoeffs = _parsePolynomial(factorStr);
final termCoeffs = _parsePolynomial(termStr, variable);
final factorCoeffs = _parsePolynomial(factorStr, variable);
final termA = termCoeffs[1] ?? 0; // x coefficient
final termB = termCoeffs[0] ?? 0; // constant term
@@ -1008,8 +1171,8 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
final rightSide = parts[1];
// 解析左边的多项式
final leftCoeffs = _parsePolynomial(leftSide);
final rightCoeffs = _parsePolynomial(rightSide);
final leftCoeffs = _parsePolynomial(leftSide, variable);
final rightCoeffs = _parsePolynomial(rightSide, variable);
// 计算标准形式 ax^2 + bx + c = 0 的系数
// A = B 转换为 A - B = 0所以右边的系数要取相反数
@@ -1051,12 +1214,15 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
return result;
}
LinearEquationParts _parseLinearEquation(String input) {
LinearEquationParts _parseLinearEquation(
String input, [
String variable = 'x',
]) {
final parts = input.split('=');
if (parts.length != 2) throw Exception("方程格式错误,应包含一个'='。");
final leftCoeffs = _parsePolynomial(parts[0]);
final rightCoeffs = _parsePolynomial(parts[1]);
final leftCoeffs = _parsePolynomial(parts[0], variable);
final rightCoeffs = _parsePolynomial(parts[1], variable);
return LinearEquationParts(
(leftCoeffs[1] ?? 0.0),
@@ -1066,7 +1232,7 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
);
}
Map<int, double> _parsePolynomial(String side) {
Map<int, double> _parsePolynomial(String side, [String variable = 'x']) {
final coeffs = <int, double>{};
// 如果输入包含括号,去掉括号
@@ -1075,9 +1241,12 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
cleanSide = cleanSide.substring(1, cleanSide.length - 1);
}
// 扩展模式以支持 sqrt 函数
// 扩展模式以支持 sqrt 函数,使用动态变量
final escapedVar = RegExp.escape(variable);
final pattern = RegExp(
r'([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))x(?:\^(\d+))?|([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))',
r'([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))' +
escapedVar +
r'(?:\^(\d+))?|([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))',
);
var s = cleanSide.startsWith('+') || cleanSide.startsWith('-')
? cleanSide
@@ -1092,7 +1261,7 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
final constValue = _parseCoefficientWithSqrt(constStr);
coeffs[0] = (coeffs[0] ?? 0) + constValue;
} else {
// x 的幂次项
// 变量的幂次项
int power = match.group(2) != null ? int.parse(match.group(2)!) : 1;
String coeffStr = match.group(1) ?? '+';
final coeff = _parseCoefficientWithSqrt(coeffStr);
@@ -1453,19 +1622,24 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
final intValue = value.toInt();
if (value == intValue.toDouble()) {
// 尝试找到最大的完全平方因子
int maxK = 1;
int maxSquareRoot = 1;
for (int k = 2; k * k <= intValue; k++) {
if (intValue % (k * k) == 0) {
maxK = k;
maxSquareRoot = k;
}
}
if (maxK > 1) {
final remaining = intValue ~/ (maxK * maxK);
if (maxSquareRoot > 1) {
final remaining = intValue ~/ (maxSquareRoot * maxSquareRoot);
if (remaining > 1) {
return '$maxK\\sqrt{$remaining}';
return '$maxSquareRoot\\sqrt{$remaining}';
} else if (remaining == 1) {
return '$maxSquareRoot';
}
}
// 如果是整数但不是完全平方数,且没有找到 k√m 形式,返回 √value
return '\\sqrt{$intValue}';
}
return null; // 无法用简单符号形式表示
@@ -1614,4 +1788,188 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
if (r.denominator == BigInt.one) return r.numerator.toString();
return '\\frac{${r.numerator}}{${r.denominator}}';
}
/// 从因式分解形式计算二次方程的根
({String formula, String finalAnswer}) _calculateRootsFromFactoredForm(
String factored,
) {
// 解析因式分解形式,如 "(2x + 4)(x - 3)" 或 "(x - 1)(x - 1)"
final factorMatch = RegExp(r'\(([^)]+)\)\(([^)]+)\)').firstMatch(factored);
if (factorMatch == null) {
return (formula: '\$\$无法解析因式形式\$\$', finalAnswer: '\$\$无法解析因式形式\$\$');
}
final factor1 = factorMatch.group(1)!;
final factor2 = factorMatch.group(2)!;
// 简化解析:直接从字符串中提取系数
double a1 = 1, b1 = 0;
double a2 = 1, b2 = 0;
// 解析第一个因式
final f1 = factor1.replaceAll(' ', '');
if (f1.contains('x')) {
final parts = f1.split('x');
if (parts[0].isEmpty || parts[0] == '+') {
a1 = 1;
} else if (parts[0] == '-') {
a1 = -1;
} else {
a1 = double.parse(parts[0]);
}
if (parts.length > 1 && parts[1].isNotEmpty) {
b1 = double.parse(parts[1]);
}
} else {
// 常数项
b1 = double.parse(f1);
a1 = 0;
}
// 解析第二个因式
final f2 = factor2.replaceAll(' ', '');
if (f2.contains('x')) {
final parts = f2.split('x');
if (parts[0].isEmpty || parts[0] == '+') {
a2 = 1;
} else if (parts[0] == '-') {
a2 = -1;
} else {
a2 = double.parse(parts[0]);
}
if (parts.length > 1 && parts[1].isNotEmpty) {
b2 = double.parse(parts[1]);
}
} else {
// 常数项
b2 = double.parse(f2);
a2 = 0;
}
// 计算根x = -b/a 对于每个因式
String root1, root2;
if (a1 != 0) {
final root1Rat = _rationalFromDouble(-b1 / a1);
root1 = _formatRational(root1Rat);
} else {
root1 = 'undefined';
}
if (a2 != 0) {
final root2Rat = _rationalFromDouble(-b2 / a2);
root2 = _formatRational(root2Rat);
} else {
root2 = 'undefined';
}
// 检查是否为重根
final formula = root1 == root2
? '\$\$x_1 = x_2 = $root1\$\$'
: '\$\$x_1 = $root1, \\quad x_2 = $root2\$\$';
final finalAnswer = root1 == root2
? '\$\$x_1 = x_2 = $root1\$\$'
: '\$\$x_1 = $root1, \\quad x_2 = $root2\$\$';
return (formula: formula, finalAnswer: finalAnswer);
}
/// 使用公式法求解一元二次方程
CalculationResult _solveQuadraticByFormula(
double a,
double b,
double c,
List<CalculationStep> steps,
) {
// Step 3: 计算判别式
final discriminant = b * b - 4 * a * c;
steps.add(
CalculationStep(
stepNumber: 3,
title: '计算判别式',
explanation: '判别式 Δ = b² - 4ac用于判断方程根的情况。',
formula:
'\$\$\\Delta = b^2 - 4ac = $b^2 - 4 \\cdot $a \\cdot $c = $discriminant\$\$',
),
);
// Step 4: 应用公式法
final denominator = 2 * a;
final sqrtDiscriminant = sqrt(discriminant.abs());
String formula;
String finalAnswer;
if (discriminant > 0) {
// 两个实数根 - 使用有理数计算并化简
final x1 = (-b + sqrtDiscriminant) / denominator;
final x2 = (-b - sqrtDiscriminant) / denominator;
// 尝试使用有理数精确计算
final aRat = _rationalFromDouble(a);
final bRat = _rationalFromDouble(b);
final cRat = _rationalFromDouble(c);
final discriminantRat =
bRat * bRat - Rational(BigInt.from(4)) * aRat * cRat;
final sqrtRat = sqrtRational(discriminantRat);
if (sqrtRat != null) {
// 使用精确有理数计算
final x1Rat = (-bRat + sqrtRat) / (Rational(BigInt.from(2)) * aRat);
final x2Rat = (-bRat - sqrtRat) / (Rational(BigInt.from(2)) * aRat);
final x1Str = _formatRational(x1Rat);
final x2Str = _formatRational(x2Rat);
formula =
'\$\$x = \\frac{-b \\pm \\sqrt{\\Delta}}{2a} = \\frac{${-b} \\pm \\sqrt{$discriminant}}{$denominator}\$\$';
finalAnswer = '\$\$x_1 = $x1Str, \\quad x_2 = $x2Str\$\$';
} else {
// 回退到数值计算
formula =
'\$\$x = \\frac{-b \\pm \\sqrt{\\Delta}}{2a} = \\frac{${-b} \\pm \\sqrt{$discriminant}}{$denominator}\$\$';
finalAnswer = '\$\$x_1 = $x1, \\quad x_2 = $x2\$\$';
}
} else if (discriminant == 0) {
// 尝试使用有理数计算
final aRat = _rationalFromDouble(a);
final bRat = _rationalFromDouble(b);
final xRat = -bRat / (Rational(BigInt.from(2)) * aRat);
final xStr = _formatRational(xRat);
formula = '\$\$x = \\frac{-b}{2a} = \\frac{${-b}}{$denominator}\$\$';
finalAnswer = '\$\$x = $xStr\$\$';
} else {
// 两个虚数根
final imagPart = sqrtDiscriminant / denominator.abs();
// 尝试使用有理数计算实部
final aRat = _rationalFromDouble(a);
final bRat = _rationalFromDouble(b);
final realPartRat = -bRat / (Rational(BigInt.from(2)) * aRat);
final realPartStr = _formatRational(realPartRat);
formula =
'\$\$x = \\frac{-b \\pm \\sqrt{\\Delta}}{2a} = \\frac{${-b} \\pm \\sqrt{$discriminant}}{$denominator}\$\$';
finalAnswer =
'\$\$x_1 = $realPartStr + ${imagPart}i, \\quad x_2 = $realPartStr - ${imagPart}i\$\$';
}
steps.add(
CalculationStep(
stepNumber: 4,
title: '应用公式法',
explanation: discriminant > 0
? '判别式大于0有两个不相等的实数根。'
: discriminant == 0
? '判别式等于0有两个相等的实数根。'
: '判别式小于0在实数范围内无解但有虚数根。',
formula: formula,
),
);
return CalculationResult(steps: steps, finalAnswer: finalAnswer);
}
}