Compare commits
3 Commits
47b6fb853a
...
1455c0b98c
Author | SHA1 | Date | |
---|---|---|---|
1455c0b98c
|
|||
1b80702bbe
|
|||
ac101a2f0e
|
514
lib/solver.dart
514
lib/solver.dart
@@ -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('x²')) {
|
||||
return _solveQuadraticEquation(processedInput.replaceAll('x²', '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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user