From ac99a94398e954ee0e9bc2dc87d1b1eeb004a6e3 Mon Sep 17 00:00:00 2001 From: spadek <1437921734@qq.com> Date: Wed, 10 Apr 2019 20:29:15 +0800 Subject: [PATCH] ... --- lib/src/command/handleEquations.dart | 136 ++++-------- lib/src/command/handleNonlinearEquation.dart | 142 ------------- lib/src/language/xiaomingLocalizations.dart | 20 +- lib/src/view/route/equationRoute.dart | 39 ++-- lib/src/view/route/integralRoute.dart | 207 ++++++++++--------- lib/src/view/widget/myTabScaffold.dart | 12 +- test/testCommand.dart | 26 +-- 7 files changed, 195 insertions(+), 387 deletions(-) delete mode 100644 lib/src/command/handleNonlinearEquation.dart diff --git a/lib/src/command/handleEquations.dart b/lib/src/command/handleEquations.dart index 967fab2..1a93280 100644 --- a/lib/src/command/handleEquations.dart +++ b/lib/src/command/handleEquations.dart @@ -11,68 +11,46 @@ class EquationsUtil { return instance; } ///处理方程计算,判断是 - String handleEquation(String equations, String xs){ + String handleEquation(String equations){ String result; - if(equations.contains('^')){ - result = _nonlinearEquation(equations, xs); - }else{ - result = _handleLineEquations(equations, xs); + if(equations.contains(';')){ + result = _handleLineEquations(equations); + }else { + result = _nonlinearEquation(equations); } return result; } ///传入线性方程组和变量求得结果 ///@param raweuations 线性方程组,以逗号隔开 ///@param rawvars 所有变量,以逗号隔开 - String _handleLineEquations(String raweuations, String rawvars) { - RegExp char = new RegExp(r'^[A-Za-z]+[0-9]*'); - var varmap = new Map(); + String _handleLineEquations(String euationsStr) { String result = ''; - var index = 0; - var equations = raweuations.split(','); - var vars = rawvars.split(','); - if (equations.length != vars.length) { - return '方程个数应与未知数个数相等'; - } - for (int i = 0; i < vars.length; i++) { - postMatrix.add([]); - constant.add([]); - constant[i].add(0); - for (int j = 0; j < vars.length; j++) { - postMatrix[i].add(0); - } - } - for (var v in vars) { - if (!char.hasMatch(v)) { - return '变量必须以字母开头,数字只能放在结尾位置'; - } - varmap[v] = index; - index++; - } - var equationIndex = 0; - for (var equation in equations) { - var reg = RegExp(r'='); - var matchs = reg.allMatches(equation); - if (matchs.length != 1) { - return '方程中等号数量错误'; - } - if (equation.contains(RegExp(r'\*|/'))) { - return '线性方程组不处理乘除运算'; - } - var lr = equation.split('='); - var leftEquation = lr[0]; - var rightEquation = lr[1]; - try{ - _simplifiedEquation(leftEquation, varmap, true, equationIndex); - _simplifiedEquation(rightEquation, varmap, false, equationIndex); - }catch(e){ - return e.toString(); + var equations = euationsStr.split(';'); + var length = equations[0].split(',').length; + var postMatrix = >[]; + var constant = >[]; + try{ + for (int i = 0; i < equations.length; i++) { + postMatrix.add([]); + constant.add([]); + var ns = equations[i].split(','); + if(length != ns.length) return '第 ${i+1} 行参数数量与第一行不一致'; + for (int j = 0; j < ns.length; j++) { + if (j != ns.length - 1){ + postMatrix[i].add(num.parse(ns[j])); + }else { + constant[i].add(num.parse(ns[j])); + } + } } - equationIndex++; + }catch (e){ + return '系数阵输入有误'; } + var resultList = MatrixUtil.m2mRide(MatrixUtil.getAdjoint(postMatrix), constant); var sb = new StringBuffer(); - for(int i=0;i maxPower) { - maxPower = power; - } - }else{ - power = 1; - } - if (map.containsKey(power)) { - map[power] += post; + String _nonlinearEquation(String equation){ + var nums = equation.split(','); + var list = []; + for(var n in nums) { + var temp = num.tryParse(n); + if(temp != null) { + list.add(temp); } else { - map[power] = post; - } - } - var numMs = numReg.allMatches(equation); - for(var m in numMs){ - num temp = num.tryParse(m.group(0)); - if(temp != null){ - c += temp; + return "$n 不能被识别为数字"; } } + var maxPower = list.length - 1; List> matrix = MatrixUtil.initMatrix(maxPower, maxPower); ///将多项式的最高次幂项系数化为1 - matrix[0][maxPower - 1] = -(c / map[maxPower]); + matrix[0][maxPower - 1] = -(list[list.length - 1] / list[maxPower]); for(int i=maxPower - 1;i>0;i--){ - if(!map.containsKey(i)){ - map[i] = 0; - }else{ - map[i] = map[i] / map[maxPower]; - } - matrix[0][maxPower - i - 1] = -map[i]; + list[i] = list[i] / list[maxPower]; + matrix[0][maxPower - i - 1] = -list[i]; } for(int i=1;i stack = []; - for (int i = 0; i < caculStr.length; i++) { - if (caculStr[i] == '(') { - if (stack.length == 0) { - caculStrs.add(new StringBuffer()); - index++; - } - stack.add('('); - if (stack.length == 1) { - continue; - } - } - if (caculStr[i] == ')') { - stack.removeLast(); - if (stack.length == 0) continue; - } - if (stack.length != 0) { - caculStrs[index].write(caculStr[i]); - } - } - - if (caculStrs.length != 0) { - for (int i = 0; i < caculStrs.length; i++) { - caculStr = caculStr.replaceFirst( - '(' + caculStrs[i].toString() + ')', 'caculStrTemp$i'); - temp['caculStrTemp$i'] = handleCalcuStr(caculStrs[i].toString()); - } - } - } - RegExp oper = new RegExp(r'(\+|-|\*|/|\^)'); - List varibales = caculStr.split(oper); - //存储运算符的列表 - Iterable opers = oper.allMatches(caculStr); - List operStrs = []; - //运算符列表 - for (Match m in opers) { - operStrs.add(m.group(0)); - } - //运算数列表 - List nums = []; - for (String str in varibales) { - if (num.tryParse(str) == null) { - if (!temp.containsKey(str)) { - throw FormatException('未知的符号: $str'); - } else { - nums.add(temp[str]); - } - } else { - nums.add(num.tryParse(str)); - } - } - //根据运算符优先级调用运算符运算,直到运算符列表中没有值时返回运算值列表中的第一个数 - while (operStrs.length != 0) { - String oper = _handleOperStrs(operStrs); - int index = operStrs.indexOf(oper); - operStrs.removeAt(index); - var num1 = nums.removeAt(index); - var num2 = nums.removeAt(index); - nums.insert(index, _handleCacul(num1, num2, oper)); - } - return nums[0]; - } - - String _handleOperStrs(List operStrs) { - //先乘除再加减 - for (String oper in operStrs) { - if (oper == '^') return oper; - } - for (String oper in operStrs) { - if (oper == '*' || oper == '/') return oper; - } - return operStrs[0]; - } - - /// 处理两个值计算 - dynamic _handleCacul(dynamic num1, dynamic num2, String oper) { - if (num1 is num) { - if (num2 is num) { - //两个浮点数运算 - switch (oper) { - case '*': - return num1 * num2; - case '/': - return num1 / num2; - case '+': - return num1 + num2; - case '-': - return num1 - num2; - case '^': - return pow(num1, num2); - } - } else { - throw FormatException('未知的符号: $num2'); - } - } else { - throw FormatException('未知的符号: $num1'); - } - } -} diff --git a/lib/src/language/xiaomingLocalizations.dart b/lib/src/language/xiaomingLocalizations.dart index 73958fc..fc206ab 100644 --- a/lib/src/language/xiaomingLocalizations.dart +++ b/lib/src/language/xiaomingLocalizations.dart @@ -24,10 +24,11 @@ class XiaomingLocalizations { 'empty': 'empty', 'equations' : 'Equations', 'equationNotEmpty' : 'Equations cannot be empty', + 'equationTip' : 'Tip: this page can be used to solve linear equations and higher-order unary equations', 'equaHint1': 'A linear equation is one or more equations whose highest power is one', - 'equaHint2': 'Example a00x + + a02z a01y = b0, a10x + + a12z a11y = b1,', - 'equaHint3': 'a20x +a21y+a22z=b2 ', + 'equaHint2': 'Example 3x-2y+z=2,3y+5z=8,', + 'equaHint3': 'Multiple equation are separated by commas, Parameter is x,y,z', 'equaHint4': 'Polynomials refer to equations of one variable multiple times', 'equaHint5': "Example: x^2-2x+1", @@ -63,6 +64,7 @@ class XiaomingLocalizations { 'parameter' : 'parameter', 'removeUF' : 'UserFuntion has been removed', 'removeData' : 'Data has been removed', + 'sample' : 'Sample', 'Setting': 'Setting', 'save' : 'save', 'Saved function': 'Saved function', @@ -90,9 +92,10 @@ class XiaomingLocalizations { 'empty': '清空', 'equations' : '方程', 'equationNotEmpty' : '方程组不能为空', + 'equationTip' : '提示:本页面可求解线性方程组和一元高次方程', 'equaHint1': '线性方程指最高次幂为1次的一元或多元方程', - 'equaHint2': '例a00x+a01y+a02z=b0,a10x+a11y+a12z=b1,', - 'equaHint3': 'a20x+a21y+a22z=b2 变量栏输入x,y,z', + 'equaHint2': '例: 3x-2y+z=2,3y+5z=8,', + 'equaHint3': '多个方程用逗号分隔,变量栏输入x,y,z', 'equaHint4': '多项式指一元多次方程', 'equaHint5': "例:'x^2-2x+1' ,变量栏输入x", 'funName' : '函数名', @@ -133,6 +136,7 @@ class XiaomingLocalizations { 'parameter' : '参数', 'removeUF' : '自定义方法被移除', 'removeData' : '数据被移除', + 'sample' : '示例', 'Setting': '设置', 'save' : '保存', 'Saved function': '保存的函数', @@ -205,6 +209,10 @@ class XiaomingLocalizations { return _localizedValues[locale.languageCode]['equations']; } + get equationTip { + return _localizedValues[locale.languageCode]['equationTip']; + } + get equaHint1 { return _localizedValues[locale.languageCode]['equaHint1']; } @@ -333,6 +341,10 @@ class XiaomingLocalizations { return _localizedValues[locale.languageCode]['removeData']; } + get sample { + return _localizedValues[locale.languageCode]['sample']; + } + get savedFunction { return _localizedValues[locale.languageCode]['Saved function']; } diff --git a/lib/src/view/route/equationRoute.dart b/lib/src/view/route/equationRoute.dart index 6f83808..df11533 100644 --- a/lib/src/view/route/equationRoute.dart +++ b/lib/src/view/route/equationRoute.dart @@ -1,3 +1,4 @@ +import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:xiaoming/src/command/handleEquations.dart'; @@ -34,15 +35,15 @@ class _EquationRouteState extends State Widget build(BuildContext context) { UserData.nowPage = 1; UserData.pageContext = context; - Widget _page1() { - return ListView( + + Widget _buildListView() { + return Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox( - height: 80.0, - ), + Text(XiaomingLocalizations.of(context).equationTip), + SizedBox(height: 50.0,), Container( - //方程输入窗口 - padding: EdgeInsets.only(left: 12.0, bottom: 50.0), + padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 40.0), child: CupertinoTextField( clearButtonMode: OverlayVisibilityMode.editing, focusNode: _lineQuasFocusNode, @@ -57,10 +58,7 @@ class _EquationRouteState extends State ), ), Container( - padding: EdgeInsets.only( - left: 12.0, - bottom: 50.0, - ), + padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 40.0), child: CupertinoTextField( clearButtonMode: OverlayVisibilityMode.editing, focusNode: _varFocusNode, @@ -76,8 +74,7 @@ class _EquationRouteState extends State ), Container( padding: const EdgeInsets.symmetric( - horizontal: 50.0, - vertical: 20.0, + vertical: 40.0, ), child: CupertinoButton( color: Colors.blue, @@ -86,7 +83,7 @@ class _EquationRouteState extends State ), ), Container( - padding: const EdgeInsets.only(top: 40.0), + padding: const EdgeInsets.only(top: 20.0), child: Center( child: GestureDetector( onLongPress: () { @@ -137,7 +134,7 @@ class _EquationRouteState extends State trailing: buildTrailingBar([ CupertinoButton( padding: EdgeInsets.zero, - child: Icon(CupertinoIcons.info), + child: Text(XiaomingLocalizations.of(context).sample), onPressed: () { showDialog( context: context, @@ -167,11 +164,11 @@ class _EquationRouteState extends State _lineQuasFocusNode.unfocus(); _varFocusNode.unfocus(); }, - child: Center( - child: SizedBox( - height: MediaQuery.of(context).size.height * 5 / 6, - width: MediaQuery.of(context).size.width * 5 / 6, - child: _page1(), + child: SingleChildScrollView( + child: Container( + height: MediaQuery.of(context).size.height - + MediaQueryData.fromWindow(window).padding.top, + child: _buildListView(), ), ), ), @@ -186,7 +183,7 @@ class _EquationRouteState extends State if (_varController.text.length != 0) { EquationsUtil handle = EquationsUtil.getInstance(); var re = handle.handleEquation( - _lineQuasController.text, _varController.text); + _lineQuasController.text); setState(() { result = re; }); diff --git a/lib/src/view/route/integralRoute.dart b/lib/src/view/route/integralRoute.dart index 20436ff..eb5b127 100644 --- a/lib/src/view/route/integralRoute.dart +++ b/lib/src/view/route/integralRoute.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -69,116 +71,123 @@ class _IntegralRouteState extends State { child: Icon(CupertinoIcons.info), ), ), - child: Container( - padding: const EdgeInsets.all(12.0), - child: ListView( - children: [ - SizedBox( - height: 80.0, - ), - Container( - //方程输入窗口 - padding: EdgeInsets.only(left: 12.0, bottom: 50.0), - child: CupertinoTextField( - clearButtonMode: OverlayVisibilityMode.editing, - controller: _dController, - textCapitalization: TextCapitalization.words, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 0.0, color: CupertinoColors.black)), + child: SingleChildScrollView( + child: Container( + height: MediaQuery.of(context).size.height - + MediaQueryData.fromWindow(window).padding.top, + padding: const EdgeInsets.all(12.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + //方程输入窗口 + padding: EdgeInsets.only(left: 12.0, bottom: 50.0), + child: CupertinoTextField( + clearButtonMode: OverlayVisibilityMode.editing, + controller: _dController, + textCapitalization: TextCapitalization.words, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 0.0, color: CupertinoColors.black)), + ), + placeholder: + XiaomingLocalizations.of(context).integralFunction, ), - placeholder: - XiaomingLocalizations.of(context).integralFunction, - ), - ), - Container( - padding: EdgeInsets.only( - left: 12.0, - bottom: 50.0, ), - child: CupertinoTextField( - clearButtonMode: OverlayVisibilityMode.editing, - controller: _pController, - textCapitalization: TextCapitalization.words, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 0.0, color: CupertinoColors.black)), + Container( + padding: EdgeInsets.only( + left: 12.0, + bottom: 50.0, ), - placeholder: - XiaomingLocalizations.of(context).integralVariable, - ), - ), - Container( - padding: EdgeInsets.only( - left: 12.0, - bottom: 50.0, - ), - child: CupertinoTextField( - clearButtonMode: OverlayVisibilityMode.editing, - controller: _iController, - textCapitalization: TextCapitalization.words, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 0.0, color: CupertinoColors.black)), + child: CupertinoTextField( + clearButtonMode: OverlayVisibilityMode.editing, + controller: _pController, + textCapitalization: TextCapitalization.words, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 0.0, color: CupertinoColors.black)), + ), + placeholder: + XiaomingLocalizations.of(context).integralVariable, ), - placeholder: XiaomingLocalizations.of(context).integralRange + - ' ps: 3,5', ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 50.0, - vertical: 20.0, + Container( + padding: EdgeInsets.only( + left: 12.0, + bottom: 50.0, + ), + child: CupertinoTextField( + clearButtonMode: OverlayVisibilityMode.editing, + controller: _iController, + textCapitalization: TextCapitalization.words, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 0.0, color: CupertinoColors.black)), + ), + placeholder: + XiaomingLocalizations.of(context).integralRange + + ' ps: 3,5', + ), ), - child: CupertinoButton( - color: Colors.blue, - onPressed: () { - setState(() { - isReady = false; - }); - getResult().then((str) { + Container( + padding: const EdgeInsets.symmetric( + horizontal: 50.0, + vertical: 20.0, + ), + child: CupertinoButton( + color: Colors.blue, + onPressed: () { setState(() { - result = str; - isReady = true; + isReady = false; + }); + getResult().then((str) { + setState(() { + result = str; + isReady = true; + }); }); - }); - }, - child: Text(XiaomingLocalizations.of(context).calculate), + }, + child: Text(XiaomingLocalizations.of(context).calculate), + ), ), - ), - Container( - padding: const EdgeInsets.only(top: 40.0), - child: Center( - child: isReady - ? GestureDetector( - onLongPress: () { - Clipboard.setData(new ClipboardData(text: result)); - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - XiaomingLocalizations.of(context) - .copyHint), - ); - }); - }, - child: Text( - result, - style: - TextStyle(color: Colors.purple, fontSize: 20.0), + Container( + padding: const EdgeInsets.only(top: 40.0), + child: Center( + child: isReady + ? GestureDetector( + onLongPress: () { + Clipboard.setData( + new ClipboardData(text: result)); + showDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text( + XiaomingLocalizations.of(context) + .copyHint), + ); + }); + }, + child: Text( + result, + style: TextStyle( + color: Colors.purple, fontSize: 20.0), + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CupertinoActivityIndicator(), + Text("正在计算中"), + ], ), - ) - : Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - CupertinoActivityIndicator(), - Text("正在计算中"), - ],), + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/src/view/widget/myTabScaffold.dart b/lib/src/view/widget/myTabScaffold.dart index 6bd68cd..1e5b140 100644 --- a/lib/src/view/widget/myTabScaffold.dart +++ b/lib/src/view/widget/myTabScaffold.dart @@ -34,14 +34,14 @@ final Widget myTabScaffold = WillPopScope( icon: Icon(Icons.message), title: Text("Home"), ), - BottomNavigationBarItem( - icon: Icon(Icons.save), - title: Text("Saved"), - ), BottomNavigationBarItem( icon: Icon(Icons.apps), title: Text("Functions"), ), + BottomNavigationBarItem( + icon: Icon(Icons.save), + title: Text("Saved"), + ), ]), tabBuilder: (BuildContext context, int index) { switch (index) { @@ -52,11 +52,11 @@ final Widget myTabScaffold = WillPopScope( break; case 1: return CupertinoTabView(builder: (BuildContext context) { - return DataRoute(); + return FunctionsRoute(); }); case 2: return CupertinoTabView(builder: (BuildContext context) { - return FunctionsRoute(); + return DataRoute(); }); } }), diff --git a/test/testCommand.dart b/test/testCommand.dart index 4e453bc..a86e765 100644 --- a/test/testCommand.dart +++ b/test/testCommand.dart @@ -1,12 +1,17 @@ +import 'package:flutter_test/flutter_test.dart'; import 'package:xiaoming/src/command/cmdMethod.dart'; import 'package:xiaoming/src/command/handleEquations.dart'; -import 'package:xiaoming/src/command/handleNonlinearEquation.dart'; import 'package:xiaoming/src/command/matrix.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:xiaoming/src/data/appData.dart'; void main() { final ud = new UserData(); + + test('testEquation', () { + var instance = EquationsUtil.getInstance(); + print(instance.handleEquation('1,-2,1')); + }); + test('userFunction', () { String cmd = 'Fun test(x,y):x*y'; print(ud.handleCommand(cmd)); @@ -30,12 +35,6 @@ void main() { ud.handleCommand('Fun test(x): r = 3*x ^ 2'); expect(ud.handleCommand('calculus(test,0,4)'), '64.000000'); }); - - test('test _nonlinearEquation', (){ - String cmd = 'x^2-2x+1'; - var instance = EquationsUtil.getInstance(); - expect(instance.handleEquation(cmd, 'x'), '第1个解为: 1.000000\n第2个解为: 1.000000\n'); - }); test('test getHessenberg', (){ List> matrix = [[4,1,0],[1,0,-1],[1,1,-4]]; @@ -51,17 +50,6 @@ void main() { [1.9999999616497233, 0.00006904586138525003]]); }); - test('test handleNonlinearEquation', () { - NonlinearEquationUtil instance = NonlinearEquationUtil.getInstance(); - var result = instance.handleNonlinearEquation('-3x^3+5x-10', 'x'); - expect(result, '-3*x^3+5*x-10'); - }); - - test('test NonlinearEquationUtil.handleCaculStr', () { - NonlinearEquationUtil instance = NonlinearEquationUtil.getInstance(); - var result = instance.handleCalcuStr('-2+4*(-3+4)'); - expect(result, 2); - }); test('test handleCaculStr', () { var result = ud.handleCalcuStr('-2+4*(-3+4)'); expect(result, 2);