♻️ Replace the math expressions with own calculator
This commit is contained in:
		| @@ -7,6 +7,9 @@ abstract class Expr { | |||||||
|   /// 新增:对表达式进行“求值/数值化”——尽可能把可算的部分算出来 |   /// 新增:对表达式进行“求值/数值化”——尽可能把可算的部分算出来 | ||||||
|   Expr evaluate(); |   Expr evaluate(); | ||||||
|  |  | ||||||
|  |   /// Substitute variable with value | ||||||
|  |   Expr substitute(String varName, Expr value); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString(); |   String toString(); | ||||||
|  |  | ||||||
| @@ -27,6 +30,9 @@ class IntExpr extends Expr { | |||||||
|   @override |   @override | ||||||
|   Expr evaluate() => this; |   Expr evaluate() => this; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => this; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => value.toString(); |   String toString() => value.toString(); | ||||||
| } | } | ||||||
| @@ -42,10 +48,31 @@ class DoubleExpr extends Expr { | |||||||
|   @override |   @override | ||||||
|   Expr evaluate() => this; |   Expr evaluate() => this; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => this; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => value.toString(); |   String toString() => value.toString(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // === VarExpr === | ||||||
|  | class VarExpr extends Expr { | ||||||
|  |   final String name; | ||||||
|  |   VarExpr(this.name); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr simplify() => this; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr evaluate() => this; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => name == varName ? value : this; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String toString() => name; | ||||||
|  | } | ||||||
|  |  | ||||||
| // === FractionExpr.evaluate === | // === FractionExpr.evaluate === | ||||||
| class FractionExpr extends Expr { | class FractionExpr extends Expr { | ||||||
|   final int numerator; |   final int numerator; | ||||||
| @@ -74,6 +101,9 @@ class FractionExpr extends Expr { | |||||||
|   @override |   @override | ||||||
|   Expr evaluate() => simplify(); |   Expr evaluate() => simplify(); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => this; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "$numerator/$denominator"; |   String toString() => "$numerator/$denominator"; | ||||||
| } | } | ||||||
| @@ -150,6 +180,12 @@ class AddExpr extends Expr { | |||||||
|     return AddExpr(l, r); |     return AddExpr(l, r); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => AddExpr( | ||||||
|  |     left.substitute(varName, value), | ||||||
|  |     right.substitute(varName, value), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "($left + $right)"; |   String toString() => "($left + $right)"; | ||||||
| } | } | ||||||
| @@ -213,6 +249,12 @@ class SubExpr extends Expr { | |||||||
|     return SubExpr(l, r); |     return SubExpr(l, r); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => SubExpr( | ||||||
|  |     left.substitute(varName, value), | ||||||
|  |     right.substitute(varName, value), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "($left - $right)"; |   String toString() => "($left - $right)"; | ||||||
| } | } | ||||||
| @@ -296,6 +338,12 @@ class MulExpr extends Expr { | |||||||
|     return MulExpr(l, r); |     return MulExpr(l, r); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => MulExpr( | ||||||
|  |     left.substitute(varName, value), | ||||||
|  |     right.substitute(varName, value), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "($left * $right)"; |   String toString() => "($left * $right)"; | ||||||
| } | } | ||||||
| @@ -378,6 +426,12 @@ class DivExpr extends Expr { | |||||||
|     return DivExpr(l, r); |     return DivExpr(l, r); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => DivExpr( | ||||||
|  |     left.substitute(varName, value), | ||||||
|  |     right.substitute(varName, value), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "($left / $right)"; |   String toString() => "($left / $right)"; | ||||||
| } | } | ||||||
| @@ -429,6 +483,10 @@ class SqrtExpr extends Expr { | |||||||
|     return SqrtExpr(i); |     return SqrtExpr(i); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => | ||||||
|  |       SqrtExpr(inner.substitute(varName, value)); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "sqrt($inner)"; |   String toString() => "sqrt($inner)"; | ||||||
| } | } | ||||||
| @@ -456,6 +514,10 @@ class CosExpr extends Expr { | |||||||
|     return CosExpr(i); |     return CosExpr(i); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => | ||||||
|  |       CosExpr(inner.substitute(varName, value)); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "cos($inner)"; |   String toString() => "cos($inner)"; | ||||||
| } | } | ||||||
| @@ -483,6 +545,10 @@ class SinExpr extends Expr { | |||||||
|     return SinExpr(i); |     return SinExpr(i); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => | ||||||
|  |       SinExpr(inner.substitute(varName, value)); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "sin($inner)"; |   String toString() => "sin($inner)"; | ||||||
| } | } | ||||||
| @@ -510,6 +576,10 @@ class TanExpr extends Expr { | |||||||
|     return TanExpr(i); |     return TanExpr(i); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Expr substitute(String varName, Expr value) => | ||||||
|  |       TanExpr(inner.substitute(varName, value)); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String toString() => "tan($inner)"; |   String toString() => "tan($inner)"; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -99,6 +99,13 @@ class Parser { | |||||||
|       return TanExpr(inner); |       return TanExpr(inner); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // 解析变量 (单个字母) | ||||||
|  |     if (RegExp(r'[a-zA-Z]').hasMatch(current)) { | ||||||
|  |       var varName = current; | ||||||
|  |       eat(); | ||||||
|  |       return VarExpr(varName); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // 解析整数 |     // 解析整数 | ||||||
|     var buf = ''; |     var buf = ''; | ||||||
|     while (!isEnd && RegExp(r'\d').hasMatch(current)) { |     while (!isEnd && RegExp(r'\d').hasMatch(current)) { | ||||||
|   | |||||||
| @@ -3,7 +3,8 @@ import 'package:latext/latext.dart'; | |||||||
| import 'package:simple_math_calc/models/calculation_step.dart'; | import 'package:simple_math_calc/models/calculation_step.dart'; | ||||||
| import 'package:simple_math_calc/solver.dart'; | import 'package:simple_math_calc/solver.dart'; | ||||||
| import 'package:fl_chart/fl_chart.dart'; | import 'package:fl_chart/fl_chart.dart'; | ||||||
| import 'package:math_expressions/math_expressions.dart' as math_expressions; | import 'package:simple_math_calc/calculator.dart'; | ||||||
|  | import 'package:simple_math_calc/parser.dart'; | ||||||
| import 'dart:math'; | import 'dart:math'; | ||||||
|  |  | ||||||
| class CalculatorHomePage extends StatefulWidget { | class CalculatorHomePage extends StatefulWidget { | ||||||
| @@ -70,11 +71,8 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> { | |||||||
|       ); |       ); | ||||||
|  |  | ||||||
|       // 解析表达式 |       // 解析表达式 | ||||||
|       final parser = math_expressions.ShuntingYardParser(); |       final parser = Parser(functionExpr); | ||||||
|       final expr = parser.parse(functionExpr); |       final expr = parser.parse(); | ||||||
|  |  | ||||||
|       // 创建变量 x |  | ||||||
|       final x = math_expressions.Variable('x'); |  | ||||||
|  |  | ||||||
|       // 根据缩放因子动态调整范围和步长 |       // 根据缩放因子动态调整范围和步长 | ||||||
|       final range = 10.0 * zoomFactor; |       final range = 10.0 * zoomFactor; | ||||||
| @@ -84,13 +82,15 @@ class _CalculatorHomePageState extends State<CalculatorHomePage> { | |||||||
|       List<FlSpot> points = []; |       List<FlSpot> points = []; | ||||||
|       for (double i = -range; i <= range; i += step) { |       for (double i = -range; i <= range; i += step) { | ||||||
|         try { |         try { | ||||||
|           final context = math_expressions.ContextModel() |           // 替换变量 x 为当前值 | ||||||
|             ..bindVariable(x, math_expressions.Number(i)); |           final substituted = expr.substitute('x', DoubleExpr(i)); | ||||||
|           final evaluator = math_expressions.RealEvaluator(context); |           final evaluated = substituted.evaluate(); | ||||||
|           final y = evaluator.evaluate(expr); |  | ||||||
|  |  | ||||||
|           if (y.isFinite && !y.isNaN) { |           if (evaluated is DoubleExpr) { | ||||||
|             points.add(FlSpot(i, y.toDouble())); |             final y = evaluated.value; | ||||||
|  |             if (y.isFinite && !y.isNaN) { | ||||||
|  |               points.add(FlSpot(i, y)); | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|           // 跳过无法计算的点 |           // 跳过无法计算的点 | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
|  |  | ||||||
|   <meta charset="UTF-8"> |   <meta charset="UTF-8"> | ||||||
|   <meta content="IE=Edge" http-equiv="X-UA-Compatible"> |   <meta content="IE=Edge" http-equiv="X-UA-Compatible"> | ||||||
|   <meta name="description" content="A new Flutter project."> |   <meta name="description" content="A simple math calculator."> | ||||||
|  |  | ||||||
|   <!-- iOS meta tags & icons --> |   <!-- iOS meta tags & icons --> | ||||||
|   <meta name="mobile-web-app-capable" content="yes"> |   <meta name="mobile-web-app-capable" content="yes"> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user