From 3f0bcb472dcaf0ef6d88572334ba33b2d8858c5c Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 14 Sep 2025 02:22:27 +0800 Subject: [PATCH] :recycle: Replaced with own calculator --- lib/solver.dart | 167 +++++++++++++++++++++++++++++++++--------- test/core_test.dart | 62 ++++++++++++++++ test/solver_test.dart | 58 +++++++++++++++ test_expand.dart | 21 ++++++ 4 files changed, 273 insertions(+), 35 deletions(-) create mode 100644 test/core_test.dart create mode 100644 test/solver_test.dart create mode 100644 test_expand.dart diff --git a/lib/solver.dart b/lib/solver.dart index 54532a3..aa86916 100644 --- a/lib/solver.dart +++ b/lib/solver.dart @@ -1,8 +1,8 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; // For kDebugMode -import 'package:math_expressions/math_expressions.dart'; import 'package:rational/rational.dart'; import 'models/calculation_step.dart'; +import 'calculator.dart'; +import 'parser.dart'; /// 帮助解析一元一次方程 ax+b=cx+d 的辅助类 class LinearEquationParts { @@ -43,9 +43,6 @@ class SolverService { try { return _solveSimpleExpression(input); // 使用原始输入以保留运算符 } catch (e) { - if (kDebugMode) { - print(e); - } throw Exception('无法识别的格式。请检查您的方程或表达式。'); } } @@ -76,17 +73,41 @@ class SolverService { // 预处理输入,将三角函数的参数从度转换为弧度 String processedInput = _convertTrigToRadians(input); - GrammarParser p = GrammarParser(); - Expression exp = p.parse(processedInput); - final result = RealEvaluator().evaluate(exp).toDouble(); + try { + // 使用自定义解析器解析表达式 + final parser = Parser(processedInput); + final expr = parser.parse(); - // 尝试将结果格式化为几倍根号的形式 - final formattedResult = _formatSqrtResult(result); + // 对表达式进行求值 + final evaluatedExpr = expr.evaluate(); - return CalculationResult( - steps: steps, - finalAnswer: '\$\$$formattedResult\$\$', - ); + // 获取数值结果 - 需要正确进行类型转换 + double result; + if (evaluatedExpr is IntExpr) { + result = evaluatedExpr.value.toDouble(); + } else if (evaluatedExpr is DoubleExpr) { + result = evaluatedExpr.value; + } else if (evaluatedExpr is FractionExpr) { + result = evaluatedExpr.numerator / evaluatedExpr.denominator; + } else { + // 如果无法完全求值为数值,尝试简化并转换为字符串 + final simplified = evaluatedExpr.simplify(); + return CalculationResult( + steps: steps, + finalAnswer: '\$\$${simplified.toString()}\$\$', + ); + } + + // 尝试将结果格式化为几倍根号的形式 + final formattedResult = _formatSqrtResult(result); + + return CalculationResult( + steps: steps, + finalAnswer: '\$\$$formattedResult\$\$', + ); + } catch (e) { + throw Exception('无法解析表达式: $input'); + } } /// 2. 求解一元一次方程 @@ -714,21 +735,28 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} if (factorMulMatch != null) { final factor1 = factorMulMatch.group(1)!; final factor2 = factorMulMatch.group(2)!; + print('Expanding: ($factor1) * ($factor2)'); + final coeffs1 = _parsePolynomial(factor1); final coeffs2 = _parsePolynomial(factor2); + print('Coeffs1: $coeffs1, Coeffs2: $coeffs2'); final a = coeffs1[1] ?? 0; final b = coeffs1[0] ?? 0; final c = coeffs2[1] ?? 0; final d = coeffs2[0] ?? 0; + print('a=$a, b=$b, c=$c, d=$d'); final newA = a * c; final newB = a * d + b * c; final newC = b * d; + print('newA=$newA, newB=$newB, newC=$newC'); final expanded = '${newA}x^2${newB >= 0 ? '+' : ''}${newB}x${newC >= 0 ? '+' : ''}$newC'; - result = result.replaceFirst(factorMulMatch.group(0)!, '($expanded)'); + print('Expanded result: $expanded'); + + result = result.replaceFirst(factorMulMatch.group(0)!, expanded); iterationCount++; continue; } @@ -762,7 +790,11 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} final newC = termB * factorB; final expanded = - '${newA}x^2${newB >= 0 ? '+' : ''}${newB}x${newC >= 0 ? '+' : ''}$newC'; + '${newA == 1 + ? '' + : newA == -1 + ? '-' + : newA}x^2${newB >= 0 ? '+' : ''}${newB}x${newC >= 0 ? '+' : ''}$newC'; result = result.replaceFirst(termFactorMatch.group(0)!, '($expanded)'); iterationCount++; continue; @@ -776,6 +808,54 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} throw Exception('表达式展开过于复杂,请简化输入。'); } + // 检查是否为方程(包含等号),如果是的话,将右边的常数项移到左边 + if (result.contains('=')) { + final parts = result.split('='); + if (parts.length == 2) { + final leftSide = parts[0]; + final rightSide = parts[1]; + + // 解析左边的多项式 + final leftCoeffs = _parsePolynomial(leftSide); + final rightCoeffs = _parsePolynomial(rightSide); + + // 计算标准形式 ax^2 + bx + c = 0 的系数 + // A = B 转换为 A - B = 0,所以右边的系数要取相反数 + final a = (leftCoeffs[2] ?? 0) - (rightCoeffs[2] ?? 0); + final b = (leftCoeffs[1] ?? 0) - (rightCoeffs[1] ?? 0); + final c = (leftCoeffs[0] ?? 0) - (rightCoeffs[0] ?? 0); + + // 构建标准形式的方程 + String standardForm = ''; + if (a != 0) { + standardForm += + '${a == 1 + ? '' + : a == -1 + ? '-' + : a}x^2'; + } + if (b != 0) { + standardForm += b > 0 ? '+${b}x' : '${b}x'; + } + if (c != 0) { + standardForm += c > 0 ? '+$c' : '$c'; + } + + // 移除开头的加号 + if (standardForm.startsWith('+')) { + standardForm = standardForm.substring(1); + } + + // 如果所有系数都为0,则方程恒成立 + if (standardForm.isEmpty) { + standardForm = '0'; + } + + result = '$standardForm=0'; + } + } + return result; } @@ -796,13 +876,24 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} Map _parsePolynomial(String side) { final coeffs = {}; + + // 如果输入包含括号,去掉括号 + var cleanSide = side; + if (cleanSide.startsWith('(') && cleanSide.endsWith(')')) { + cleanSide = cleanSide.substring(1, cleanSide.length - 1); + } + // 扩展模式以支持 sqrt 函数 final pattern = RegExp( r'([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))x(?:\^(\d+))?|([+-]?(?:\d*\.?\d*|sqrt\(\d+\)))', ); - var s = side.startsWith('+') || side.startsWith('-') ? side : '+$side'; + var s = cleanSide.startsWith('+') || cleanSide.startsWith('-') + ? cleanSide + : '+$cleanSide'; for (final match in pattern.allMatches(s)) { + if (match.group(0)!.isEmpty) continue; // Skip empty matches + if (match.group(3) != null) { // 常数项 final constStr = match.group(3)!; @@ -893,26 +984,31 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} if (a == 0) return null; int ac = a * c; int absAc = ac.abs(); + + // Try all divisors of abs(ac) and consider both positive and negative factors for (int d = 1; d <= sqrt(absAc).toInt(); d++) { if (absAc % d == 0) { int d1 = d; int d2 = absAc ~/ d; - List signs1 = ac >= 0 ? [1, -1] : [1, -1]; - List signs2 = ac >= 0 ? [1, -1] : [1, -1]; - for (int s1 in signs1) { - for (int s2 in signs2) { - int m = s1 * d1; - int n = s2 * d2; - if (check(m, n, b)) return formatFactor(m, n, a); - m = s1 * d1; - n = s2 * (-d2); - if (check(m, n, b)) return formatFactor(m, n, a); - m = s1 * (-d1); - n = s2 * d2; - if (check(m, n, b)) return formatFactor(m, n, a); - m = s1 * (-d1); - n = s2 * (-d2); - if (check(m, n, b)) return formatFactor(m, n, a); + + // Try all sign combinations for the factors + // We need m * n = ac and m + n = b + List signCombinations = [1, -1]; + + for (int sign1 in signCombinations) { + for (int sign2 in signCombinations) { + int m = sign1 * d1; + int n = sign2 * d2; + if (m + n == b && m * n == ac) { + return formatFactor(m, n, a); + } + + // Also try the swapped version + m = sign1 * d2; + n = sign2 * d1; + if (m + n == b && m * n == ac) { + return formatFactor(m, n, a); + } } } } @@ -1109,10 +1205,11 @@ ${b1}y &= ${c1 - a1 * x.toDouble()} for (int i = 0; i < s.length; i++) { final char = s[i]; - if (char == '(') + if (char == '(') { parenDepth++; - else if (char == ')') + } else if (char == ')') { parenDepth--; + } // Only split on + or - when not inside parentheses if (parenDepth == 0 && (char == '+' || char == '-') && i > start) { diff --git a/test/core_test.dart b/test/core_test.dart new file mode 100644 index 0000000..e12c28c --- /dev/null +++ b/test/core_test.dart @@ -0,0 +1,62 @@ +import 'package:test/test.dart'; +import 'package:simple_math_calc/calculator.dart'; +import 'package:simple_math_calc/parser.dart'; + +void main() { + group('解析器测试', () { + test('简单加法', () { + final parser = Parser('2 + 3'); + final expr = parser.parse(); + final result = expr.evaluate(); + expect(result.toString(), '5'); + }); + + test('乘法和加法优先级', () { + final parser = Parser('2 + 3 * 4'); + final expr = parser.parse(); + final result = expr.evaluate(); + expect(result.toString(), '14'); + }); + + test('括号优先级', () { + final parser = Parser('(2 + 3) * 4'); + final expr = parser.parse(); + final result = expr.evaluate(); + expect(result.toString(), '20'); + }); + + test('除法', () { + final parser = Parser('10 / 2'); + final expr = parser.parse(); + final result = expr.evaluate(); + expect(result.toString(), '5'); + }); + + test('平方根', () { + final parser = Parser('sqrt(9)'); + final expr = parser.parse(); + final result = expr.evaluate(); + expect(result.toString(), '3'); + }); + }); + + group('计算器测试', () { + test('分数简化', () { + final fraction = FractionExpr(4, 8); + final simplified = fraction.simplify(); + expect(simplified.toString(), '1/2'); + }); + + test('分数加法', () { + final expr = AddExpr(FractionExpr(1, 2), FractionExpr(1, 4)); + final result = expr.evaluate(); + expect(result.toString(), '3/4'); + }); + + test('分数乘法', () { + final expr = MulExpr(FractionExpr(1, 2), FractionExpr(2, 3)); + final result = expr.evaluate(); + expect(result.toString(), '1/3'); + }); + }); +} diff --git a/test/solver_test.dart b/test/solver_test.dart new file mode 100644 index 0000000..20bd9e2 --- /dev/null +++ b/test/solver_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter/widgets.dart'; +import 'package:test/test.dart'; +import 'package:simple_math_calc/solver.dart'; + +void main() { + group('求解器测试', () { + final solver = SolverService(); + + test('简单表达式求值', () { + final result = solver.solve('2 + 3 * 4'); + expect(result.finalAnswer, contains('14')); + }); + + test('简单方程求解', () { + final result = solver.solve('2x + 3 = 7'); + expect(result.finalAnswer, contains('x = 2')); + }); + + test('二次方程求解', () { + final result = solver.solve('x^2 - 5x + 6 = 0'); + debugPrint(result.finalAnswer); + expect( + result.finalAnswer.contains('x_1 = 2') && + result.finalAnswer.contains('x_2 = 3'), + true, + ); + }); + + test('三角函数求值', () { + final result = solver.solve('sin(30)'); + debugPrint(result.finalAnswer); + expect(result.finalAnswer.contains(r'\frac{1}{2}'), true); + }); + + test('带括号的复杂表达式', () { + final result = solver.solve('(2 + 3) * 4'); + expect(result.finalAnswer, contains('20')); + }); + + test('括号展开的二次方程', () { + final result = solver.solve('(x+8)(x+1)=-12'); + debugPrint('Result for (x+8)(x+1)=-12: ${result.finalAnswer}'); + // 这个方程应该被识别为一元二次方程,正确解应该是 x = -4 或 x = -5 + expect( + result.steps.any((step) => step.title == '整理方程'), + true, + reason: '方程应被识别为一元二次方程并进行整理', + ); + expect( + (result.finalAnswer.contains('-4') && + result.finalAnswer.contains('-5')) || + result.finalAnswer.contains('x = -4') || + result.finalAnswer.contains('x = -5'), + true, + ); + }); + }); +} diff --git a/test_expand.dart b/test_expand.dart new file mode 100644 index 0000000..ad93f5f --- /dev/null +++ b/test_expand.dart @@ -0,0 +1,21 @@ +import 'lib/solver.dart'; + +void main() { + final solver = SolverService(); + + // Test the problematic case + final input = '(x+8)(x+1)=-12'; + print('Input: $input'); + + try { + final result = solver.solve(input); + print('Result: ${result.finalAnswer}'); + print('Steps:'); + for (final step in result.steps) { + print('Step ${step.stepNumber}: ${step.title}'); + print(' Formula: ${step.formula}'); + } + } catch (e) { + print('Error: $e'); + } +}