🐛 Bug fixes
This commit is contained in:
149
lib/solver.dart
149
lib/solver.dart
@@ -7,13 +7,18 @@ import 'models/calculation_step.dart';
|
|||||||
|
|
||||||
/// 帮助解析一元一次方程 ax+b=cx+d 的辅助类
|
/// 帮助解析一元一次方程 ax+b=cx+d 的辅助类
|
||||||
class LinearEquationParts {
|
class LinearEquationParts {
|
||||||
final double a, b, c, d;
|
final Rational a, b, c, d;
|
||||||
LinearEquationParts(this.a, this.b, this.c, this.d);
|
LinearEquationParts(this.a, this.b, this.c, this.d);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SolverService {
|
class SolverService {
|
||||||
/// 格式化数字,移除不必要的尾随零
|
/// 格式化数字,移除不必要的尾随零
|
||||||
String _formatNumber(double value, {int precision = 4}) {
|
String _formatNumber(dynamic value, {int precision = 4}) {
|
||||||
|
if (value is Rational) {
|
||||||
|
return _formatRational(value);
|
||||||
|
} else if (value is FractionExpr) {
|
||||||
|
return '\\frac{${value.numerator}}{${value.denominator}}';
|
||||||
|
} else if (value is double) {
|
||||||
String formatted = value.toStringAsFixed(precision);
|
String formatted = value.toStringAsFixed(precision);
|
||||||
// 移除尾随的零和小数点
|
// 移除尾随的零和小数点
|
||||||
formatted = formatted.replaceAll(RegExp(r'\.0+$'), '');
|
formatted = formatted.replaceAll(RegExp(r'\.0+$'), '');
|
||||||
@@ -22,6 +27,9 @@ class SolverService {
|
|||||||
formatted = formatted.substring(0, formatted.length - 1);
|
formatted = formatted.substring(0, formatted.length - 1);
|
||||||
}
|
}
|
||||||
return formatted;
|
return formatted;
|
||||||
|
} else {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 尝试对二次方程进行因式分解
|
/// 尝试对二次方程进行因式分解
|
||||||
@@ -345,8 +353,8 @@ class SolverService {
|
|||||||
final parts = _parseLinearEquation(input, variable);
|
final parts = _parseLinearEquation(input, variable);
|
||||||
final a = parts.a, b = parts.b, c = parts.c, d = parts.d;
|
final a = parts.a, b = parts.b, c = parts.c, d = parts.d;
|
||||||
|
|
||||||
final newA = _rationalFromDouble(a) - _rationalFromDouble(c);
|
final newA = a - c;
|
||||||
final newD = _rationalFromDouble(d) - _rationalFromDouble(b);
|
final newD = d - b;
|
||||||
|
|
||||||
steps.add(
|
steps.add(
|
||||||
CalculationStep(
|
CalculationStep(
|
||||||
@@ -354,7 +362,15 @@ class SolverService {
|
|||||||
title: '移项',
|
title: '移项',
|
||||||
explanation: '将所有含 $variable 的项移到等式左边,常数项移到右边。',
|
explanation: '将所有含 $variable 的项移到等式左边,常数项移到右边。',
|
||||||
formula:
|
formula:
|
||||||
'\$\$$a$variable ${c >= 0 ? '-' : '+'} ${c.abs()}$variable = $d ${b >= 0 ? '-' : '+'} ${b.abs()}\$\$',
|
'\$\$${_formatNumber(a)}$variable ${_formatNumber(c) == '0'
|
||||||
|
? ''
|
||||||
|
: c >= Rational.zero
|
||||||
|
? '-'
|
||||||
|
: '+'} ${_formatNumber(c.abs())}$variable = ${_formatNumber(d)} ${_formatNumber(b) == '0'
|
||||||
|
? ''
|
||||||
|
: b >= Rational.zero
|
||||||
|
? '-'
|
||||||
|
: '+'} ${_formatNumber(b.abs())}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -364,7 +380,7 @@ class SolverService {
|
|||||||
title: '合并同类项',
|
title: '合并同类项',
|
||||||
explanation: '合并等式两边的项。',
|
explanation: '合并等式两边的项。',
|
||||||
formula:
|
formula:
|
||||||
'\$\$${_formatNumber(newA.toDouble())}$variable = ${_formatNumber(newD.toDouble())}\$\$',
|
'\$\$${_formatNumber(newA)}$variable = ${_formatNumber(newD)}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -380,14 +396,15 @@ class SolverService {
|
|||||||
CalculationStep(
|
CalculationStep(
|
||||||
stepNumber: 3,
|
stepNumber: 3,
|
||||||
title: '求解 $variable',
|
title: '求解 $variable',
|
||||||
explanation: '两边同时除以 $variable 的系数 ($newA)。',
|
explanation: '两边同时除以 $variable 的系数 (${_formatNumber(newA)})。',
|
||||||
formula: '\$\$$variable = \\frac{$newD}{$newA}\$\$',
|
formula:
|
||||||
|
'\$\$$variable = \\frac{${_formatNumber(newD)}}{${_formatNumber(newA)}}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return CalculationResult(
|
return CalculationResult(
|
||||||
steps: steps,
|
steps: steps,
|
||||||
finalAnswer: '\$\$$variable = $x\$\$',
|
finalAnswer: '\$\$$variable = ${_formatNumber(x)}\$\$',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,8 +818,12 @@ class SolverService {
|
|||||||
final p1 = _parseTwoVariableLinear(equations[0]);
|
final p1 = _parseTwoVariableLinear(equations[0]);
|
||||||
final p2 = _parseTwoVariableLinear(equations[1]);
|
final p2 = _parseTwoVariableLinear(equations[1]);
|
||||||
|
|
||||||
double a1 = p1[0], b1 = p1[1], c1 = p1[2];
|
final a1Rat = _rationalFromDouble(p1[0]);
|
||||||
double a2 = p2[0], b2 = p2[1], c2 = p2[2];
|
final b1Rat = _rationalFromDouble(p1[1]);
|
||||||
|
final c1Rat = _rationalFromDouble(p1[2]);
|
||||||
|
final a2Rat = _rationalFromDouble(p2[0]);
|
||||||
|
final b2Rat = _rationalFromDouble(p2[1]);
|
||||||
|
final c2Rat = _rationalFromDouble(p2[2]);
|
||||||
|
|
||||||
steps.add(
|
steps.add(
|
||||||
CalculationStep(
|
CalculationStep(
|
||||||
@@ -813,43 +834,56 @@ class SolverService {
|
|||||||
'''
|
'''
|
||||||
\$\$
|
\$\$
|
||||||
\\begin{cases}
|
\\begin{cases}
|
||||||
${a1}x ${b1 >= 0 ? '+' : ''} ${b1}y = $c1 & (1) \\\\
|
${_formatNumber(a1Rat)}x ${_formatNumber(b1Rat) == '0'
|
||||||
${a2}x ${b2 >= 0 ? '+' : ''} ${b2}y = $c2 & (2)
|
? ''
|
||||||
|
: b1Rat >= Rational.zero
|
||||||
|
? '+'
|
||||||
|
: ''} ${_formatNumber(b1Rat)}y = ${_formatNumber(c1Rat)} & (1) \\\\
|
||||||
|
${_formatNumber(a2Rat)}x ${_formatNumber(b2Rat) == '0'
|
||||||
|
? ''
|
||||||
|
: b2Rat >= Rational.zero
|
||||||
|
? '+'
|
||||||
|
: ''} ${_formatNumber(b2Rat)}y = ${_formatNumber(c2Rat)} & (2)
|
||||||
\\end{cases}
|
\\end{cases}
|
||||||
\$\$
|
\$\$
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final det =
|
final det = a1Rat * b2Rat - a2Rat * b1Rat;
|
||||||
_rationalFromDouble(a1) * _rationalFromDouble(b2) -
|
|
||||||
_rationalFromDouble(a2) * _rationalFromDouble(b1);
|
|
||||||
if (det == Rational.zero) {
|
if (det == Rational.zero) {
|
||||||
final infiniteCheck =
|
final infiniteCheck = a1Rat * c2Rat - a2Rat * c1Rat;
|
||||||
_rationalFromDouble(a1) * _rationalFromDouble(c2) -
|
|
||||||
_rationalFromDouble(a2) * _rationalFromDouble(c1);
|
|
||||||
return CalculationResult(
|
return CalculationResult(
|
||||||
steps: steps,
|
steps: steps,
|
||||||
finalAnswer: infiniteCheck == Rational.zero ? '有无穷多解' : '无解',
|
finalAnswer: infiniteCheck == Rational.zero ? '有无穷多解' : '无解',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final newA1 = _rationalFromDouble(a1) * _rationalFromDouble(b2);
|
final newA1 = a1Rat * b2Rat;
|
||||||
final newC1 = _rationalFromDouble(c1) * _rationalFromDouble(b2);
|
final newC1 = c1Rat * b2Rat;
|
||||||
final newA2 = _rationalFromDouble(a2) * _rationalFromDouble(b1);
|
final newA2 = a2Rat * b1Rat;
|
||||||
final newC2 = _rationalFromDouble(c2) * _rationalFromDouble(b1);
|
final newC2 = c2Rat * b1Rat;
|
||||||
|
|
||||||
steps.add(
|
steps.add(
|
||||||
CalculationStep(
|
CalculationStep(
|
||||||
stepNumber: 1,
|
stepNumber: 1,
|
||||||
title: '消元',
|
title: '消元',
|
||||||
explanation: '为了消去变量 y,将方程(1)两边乘以 $b2,方程(2)两边乘以 $b1。',
|
explanation:
|
||||||
|
'为了消去变量 y,将方程(1)两边乘以 ${_formatNumber(b2Rat)},方程(2)两边乘以 ${_formatNumber(b1Rat)}。',
|
||||||
formula:
|
formula:
|
||||||
'''
|
'''
|
||||||
\$\$
|
\$\$
|
||||||
\\begin{cases}
|
\\begin{cases}
|
||||||
${_formatNumber(newA1.toDouble(), precision: 2)}x ${b1 * b2 >= 0 ? '+' : ''} ${_formatNumber((b1 * b2), precision: 2)}y = ${_formatNumber(newC1.toDouble(), precision: 2)} & (3) \\\\
|
${_formatNumber(newA1)}x ${_formatNumber(b1Rat * b2Rat) == '0'
|
||||||
${_formatNumber(newA2.toDouble(), precision: 2)}x ${b1 * b2 >= 0 ? '+' : ''} ${_formatNumber((b1 * b2), precision: 2)}y = ${_formatNumber(newC2.toDouble(), precision: 2)} & (4)
|
? ''
|
||||||
|
: b1Rat * b2Rat >= Rational.zero
|
||||||
|
? '+'
|
||||||
|
: ''} ${_formatNumber(b1Rat * b2Rat)}y = ${_formatNumber(newC1)} & (3) \\\\
|
||||||
|
${_formatNumber(newA2)}x ${_formatNumber(b1Rat * b2Rat) == '0'
|
||||||
|
? ''
|
||||||
|
: b1Rat * b2Rat >= Rational.zero
|
||||||
|
? '+'
|
||||||
|
: ''} ${_formatNumber(b1Rat * b2Rat)}y = ${_formatNumber(newC2)} & (4)
|
||||||
\\end{cases}
|
\\end{cases}
|
||||||
\$\$
|
\$\$
|
||||||
''',
|
''',
|
||||||
@@ -865,7 +899,7 @@ ${_formatNumber(newA2.toDouble(), precision: 2)}x ${b1 * b2 >= 0 ? '+' : ''} ${_
|
|||||||
title: '相减',
|
title: '相减',
|
||||||
explanation: '将方程(3)减去方程(4),得到一个只含 x 的方程。',
|
explanation: '将方程(3)减去方程(4),得到一个只含 x 的方程。',
|
||||||
formula:
|
formula:
|
||||||
'\$\$(${_formatNumber(newA1.toDouble(), precision: 2)} - ${_formatNumber(newA2.toDouble(), precision: 2)})x = ${_formatNumber(newC1.toDouble(), precision: 2)} - ${_formatNumber(newC2.toDouble(), precision: 2)} \\Rightarrow ${_formatNumber(xCoeff.toDouble(), precision: 2)}x = ${_formatNumber(constCoeff.toDouble(), precision: 2)}\$\$',
|
'\$\$(${_formatNumber(newA1)} - ${_formatNumber(newA2)})x = ${_formatNumber(newC1)} - ${_formatNumber(newC2)} \\Rightarrow ${_formatNumber(xCoeff)}x = ${_formatNumber(constCoeff)}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -875,27 +909,27 @@ ${_formatNumber(newA2.toDouble(), precision: 2)}x ${b1 * b2 >= 0 ? '+' : ''} ${_
|
|||||||
stepNumber: 3,
|
stepNumber: 3,
|
||||||
title: '解出 x',
|
title: '解出 x',
|
||||||
explanation: '求解上述方程得到 x 的值。',
|
explanation: '求解上述方程得到 x 的值。',
|
||||||
formula: '\$\$x = ${_formatNumber(x.toDouble())}\$\$',
|
formula: '\$\$x = ${_formatNumber(x)}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (b1.abs() < 1e-9) {
|
if (b1Rat.abs() < Rational(BigInt.from(1), BigInt.from(1000000000))) {
|
||||||
final yCoeff = b2;
|
final yCoeff = b2Rat;
|
||||||
final yConst = c2 - a2 * x.toDouble();
|
final yConst = c2Rat - a2Rat * x;
|
||||||
final y = yConst / yCoeff;
|
final y = yConst / yCoeff;
|
||||||
steps.add(
|
steps.add(
|
||||||
CalculationStep(
|
CalculationStep(
|
||||||
stepNumber: 4,
|
stepNumber: 4,
|
||||||
title: '回代求解 y',
|
title: '回代求解 y',
|
||||||
explanation: '将 x = ${_formatNumber(x.toDouble())} 代入原方程(2)中。',
|
explanation: '将 x = ${_formatNumber(x)} 代入原方程(2)中。',
|
||||||
formula:
|
formula:
|
||||||
'''
|
'''
|
||||||
\$\$
|
\$\$
|
||||||
\\begin{aligned}
|
\\begin{aligned}
|
||||||
$a2(${_formatNumber(x.toDouble())}) + ${b2}y &= $c2 \\\\
|
${_formatNumber(a2Rat)}(${_formatNumber(x)}) + ${_formatNumber(b2Rat)}y &= ${_formatNumber(c2Rat)} \\\\
|
||||||
${a2 * x.toDouble()} + ${b2}y &= $c2 \\\\
|
${_formatNumber(a2Rat * x)} + ${_formatNumber(b2Rat)}y &= ${_formatNumber(c2Rat)} \\\\
|
||||||
${b2}y &= $c2 - ${a2 * x.toDouble()} \\\\
|
${_formatNumber(b2Rat)}y &= ${_formatNumber(c2Rat)} - ${_formatNumber(a2Rat * x)} \\\\
|
||||||
${b2}y &= ${c2 - a2 * x.toDouble()}
|
${_formatNumber(b2Rat)}y &= ${_formatNumber(c2Rat - a2Rat * x)}
|
||||||
\\end{aligned}
|
\\end{aligned}
|
||||||
\$\$
|
\$\$
|
||||||
''',
|
''',
|
||||||
@@ -906,31 +940,31 @@ ${b2}y &= ${c2 - a2 * x.toDouble()}
|
|||||||
stepNumber: 5,
|
stepNumber: 5,
|
||||||
title: '解出 y',
|
title: '解出 y',
|
||||||
explanation: '求解得到 y 的值。',
|
explanation: '求解得到 y 的值。',
|
||||||
formula: '\$\$y = ${_formatNumber(y.toDouble())}\$\$',
|
formula: '\$\$y = ${_formatNumber(y)}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return CalculationResult(
|
return CalculationResult(
|
||||||
steps: steps,
|
steps: steps,
|
||||||
finalAnswer:
|
finalAnswer:
|
||||||
'\$\$x = ${_formatNumber(x.toDouble())}, \\quad y = ${_formatNumber(y.toDouble())}\$\$',
|
'\$\$x = ${_formatNumber(x)}, \\quad y = ${_formatNumber(y)}\$\$',
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final yCoeff = b1;
|
final yCoeff = b1Rat;
|
||||||
final yConst = c1 - a1 * x.toDouble();
|
final yConst = c1Rat - a1Rat * x;
|
||||||
final y = yConst / yCoeff;
|
final y = yConst / yCoeff;
|
||||||
steps.add(
|
steps.add(
|
||||||
CalculationStep(
|
CalculationStep(
|
||||||
stepNumber: 4,
|
stepNumber: 4,
|
||||||
title: '回代求解 y',
|
title: '回代求解 y',
|
||||||
explanation: '将 x = ${_formatNumber(x.toDouble())} 代入原方程(1)中。',
|
explanation: '将 x = ${_formatNumber(x)} 代入原方程(1)中。',
|
||||||
formula:
|
formula:
|
||||||
'''
|
'''
|
||||||
\$\$
|
\$\$
|
||||||
\\begin{aligned}
|
\\begin{aligned}
|
||||||
$a1(${_formatNumber(x.toDouble())}) + ${b1}y &= $c1 \\\\
|
${_formatNumber(a1Rat)}(${_formatNumber(x)}) + ${_formatNumber(b1Rat)}y &= ${_formatNumber(c1Rat)} \\\\
|
||||||
${a1 * x.toDouble()} + ${b1}y &= $c1 \\\\
|
${_formatNumber(a1Rat * x)} + ${_formatNumber(b1Rat)}y &= ${_formatNumber(c1Rat)} \\\\
|
||||||
${b1}y &= $c1 - ${a1 * x.toDouble()} \\\\
|
${_formatNumber(b1Rat)}y &= ${_formatNumber(c1Rat)} - ${_formatNumber(a1Rat * x)} \\\\
|
||||||
${b1}y &= ${c1 - a1 * x.toDouble()}
|
${_formatNumber(b1Rat)}y &= ${_formatNumber(c1Rat - a1Rat * x)}
|
||||||
\\end{aligned}
|
\\end{aligned}
|
||||||
\$\$
|
\$\$
|
||||||
''',
|
''',
|
||||||
@@ -941,13 +975,13 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
|
|||||||
stepNumber: 5,
|
stepNumber: 5,
|
||||||
title: '解出 y',
|
title: '解出 y',
|
||||||
explanation: '求解得到 y 的值。',
|
explanation: '求解得到 y 的值。',
|
||||||
formula: '\$\$y = ${_formatNumber(y.toDouble())}\$\$',
|
formula: '\$\$y = ${_formatNumber(y)}\$\$',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return CalculationResult(
|
return CalculationResult(
|
||||||
steps: steps,
|
steps: steps,
|
||||||
finalAnswer:
|
finalAnswer:
|
||||||
'\$\$x = ${_formatNumber(x.toDouble())}, \\quad y = ${_formatNumber(y.toDouble())}\$\$',
|
'\$\$x = ${_formatNumber(x)}, \\quad y = ${_formatNumber(y)}\$\$',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1218,10 +1252,10 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
|
|||||||
final rightCoeffs = _parsePolynomial(parts[1], variable);
|
final rightCoeffs = _parsePolynomial(parts[1], variable);
|
||||||
|
|
||||||
return LinearEquationParts(
|
return LinearEquationParts(
|
||||||
(leftCoeffs[1] ?? 0.0),
|
_rationalFromDouble(leftCoeffs[1] ?? 0.0),
|
||||||
(leftCoeffs[0] ?? 0.0),
|
_rationalFromDouble(leftCoeffs[0] ?? 0.0),
|
||||||
(rightCoeffs[1] ?? 0.0),
|
_rationalFromDouble(rightCoeffs[1] ?? 0.0),
|
||||||
(rightCoeffs[0] ?? 0.0),
|
_rationalFromDouble(rightCoeffs[0] ?? 0.0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1702,7 +1736,18 @@ ${b1}y &= ${c1 - a1 * x.toDouble()}
|
|||||||
/// 格式化有理数为 LaTeX 分数形式
|
/// 格式化有理数为 LaTeX 分数形式
|
||||||
String _formatRational(Rational r) {
|
String _formatRational(Rational r) {
|
||||||
if (r.denominator == BigInt.one) return r.numerator.toString();
|
if (r.denominator == BigInt.one) return r.numerator.toString();
|
||||||
return '\\frac{${r.numerator}}{${r.denominator}}';
|
|
||||||
|
// 简化分数
|
||||||
|
final gcd = r.numerator.gcd(r.denominator);
|
||||||
|
final num = r.numerator ~/ gcd;
|
||||||
|
final den = r.denominator ~/ gcd;
|
||||||
|
|
||||||
|
// 处理负号,将其移到分子
|
||||||
|
if (den < BigInt.zero) {
|
||||||
|
return '\\frac{${-num}}{${-den}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '\\frac{$num}{$den}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从因式分解形式计算二次方程的根
|
/// 从因式分解形式计算二次方程的根
|
||||||
|
Reference in New Issue
Block a user