// tools/bisection_method.dart import 'package:flutter/material.dart'; import 'package:math_expressions/math_expressions.dart'; class BisectionMethodPage extends StatefulWidget { @override _BisectionMethodPageState createState() => _BisectionMethodPageState(); } class _BisectionMethodPageState extends State { final TextEditingController _functionController = TextEditingController(text: 'x^3 - x - 2'); final TextEditingController _aController = TextEditingController(text: '1'); final TextEditingController _bController = TextEditingController(text: '2'); final TextEditingController _toleranceController = TextEditingController(text: '0.0001'); final TextEditingController _maxIterationsController = TextEditingController(text: '100'); List _iterations = []; String _result = ''; bool _isCalculating = false; // 使用 math_expressions 库计算数学表达式 double _evaluateFunction(String function, double x) { try { // 预处理函数表达式 String exprString = function .replaceAll(' ', '') .replaceAll('×', '*') .replaceAll('÷', '/'); // 创建解析器 Parser p = Parser(); // 解析表达式 Expression expression = p.parse(exprString); // 创建上下文并绑定变量 x ContextModel contextModel = ContextModel() ..bindVariable(Variable('x'), Number(x)); // 计算表达式 double result = expression.evaluate(EvaluationType.REAL, contextModel); return result; } catch (e) { throw Exception('函数表达式解析错误: $e\n请检查表达式格式是否正确'); } } void _calculate() { setState(() { _isCalculating = true; _iterations.clear(); _result = ''; }); try { double a = double.parse(_aController.text); double b = double.parse(_bController.text); double tolerance = double.parse(_toleranceController.text); int maxIterations = int.parse(_maxIterationsController.text); String function = _functionController.text; if (a >= b) { throw Exception('区间左端点必须小于右端点'); } double fa = _evaluateFunction(function, a); double fb = _evaluateFunction(function, b); if (fa.isNaN || fb.isNaN) { throw Exception('函数在端点处计算失败,请检查表达式'); } if (fa * fb > 0) { throw Exception('函数在区间两端点必须异号\nf(a) = $fa, f(b) = $fb'); } int iteration = 0; double c = a; while ((b - a).abs() > tolerance && iteration < maxIterations) { c = (a + b) / 2; double fc = _evaluateFunction(function, c); if (fc.isNaN) { throw Exception('迭代过程中函数计算失败'); } _iterations.add('迭代 ${iteration + 1}: a=${a.toStringAsFixed(6)}, b=${b.toStringAsFixed(6)}, c=${c.toStringAsFixed(6)}, f(c)=${fc.toStringAsFixed(6)}'); if (fc.abs() < tolerance) { break; } else if (fa * fc < 0) { b = c; fb = fc; } else { a = c; fa = fc; } iteration++; } setState(() { _result = '近似解: ${c.toStringAsFixed(8)}\n' '迭代次数: $iteration\n' '最终误差: ${(b - a).abs().toStringAsFixed(8)}'; }); } catch (e) { setState(() { _result = '错误: $e'; }); } finally { setState(() { _isCalculating = false; }); } } void _clear() { setState(() { _functionController.text = 'x^3 - x - 2'; _aController.text = '1'; _bController.text = '2'; _toleranceController.text = '0.0001'; _maxIterationsController.text = '100'; _iterations.clear(); _result = ''; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('二分法求根', style: TextStyle(color: Colors.black)), backgroundColor: Colors.white, elevation: 1, iconTheme: IconThemeData(color: Colors.black), ), body: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '二分法求方程近似解', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.deepPurple), ), SizedBox(height: 16), Text( '使用方法:\n' '1. 输入函数表达式(支持: +, -, *, /, ^, sin, cos, tan, ln, e, sqrt 等)\n' '2. 输入有根区间 [a, b]\n' '3. 设置精度和最大迭代次数\n' '4. 点击计算获取近似解\n\n' '示例表达式:\n' '• x^3 - x - 2\n' '• sin(x) + cos(x)\n' '• e^x - 2\n' '• ln(x) + sqrt(x)', style: TextStyle(fontSize: 14, color: Colors.grey[600]), ), SizedBox(height: 20), // 函数输入 _buildInputField('函数 f(x)', '例如: x^3 - x - 2', _functionController), SizedBox(height: 16), Row( children: [ Expanded(child: _buildInputField('区间左端点 a', '1', _aController)), SizedBox(width: 16), Expanded(child: _buildInputField('区间右端点 b', '2', _bController)), ], ), SizedBox(height: 16), Row( children: [ Expanded(child: _buildInputField('精度 tolerance', '0.0001', _toleranceController)), SizedBox(width: 16), Expanded(child: _buildInputField('最大迭代次数', '100', _maxIterationsController)), ], ), SizedBox(height: 24), // 按钮 Row( children: [ Expanded( child: ElevatedButton( onPressed: _isCalculating ? null : _calculate, style: ElevatedButton.styleFrom( backgroundColor: Colors.deepPurple, padding: EdgeInsets.symmetric(vertical: 16), ), child: _isCalculating ? SizedBox(height: 20, width: 20, child: CircularProgressIndicator(color: Colors.white)) : Text('计算', style: TextStyle(fontSize: 16, color: Colors.white)), ), ), SizedBox(width: 16), Expanded( child: OutlinedButton( onPressed: _clear, style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16), ), child: Text('清空', style: TextStyle(fontSize: 16)), ), ), ], ), SizedBox(height: 24), // 结果展示 if (_result.isNotEmpty) ...[ Container( width: double.infinity, padding: EdgeInsets.all(16), decoration: BoxDecoration( color: _result.contains('错误') ? Colors.red[50] : Colors.green[50], borderRadius: BorderRadius.circular(8), border: Border.all(color: _result.contains('错误') ? Colors.red : Colors.green), ), child: Text( _result, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _result.contains('错误') ? Colors.red[800] : Colors.green[800] ), ), ), SizedBox(height: 16), ], // 迭代过程 if (_iterations.isNotEmpty) ...[ Text('迭代过程:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 8), Container( height: 200, decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(8), ), child: ListView.builder( itemCount: _iterations.length, itemBuilder: (context, index) { return Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( border: index > 0 ? Border(top: BorderSide(color: Colors.grey[200]!)) : null, color: index % 2 == 0 ? Colors.grey[50] : Colors.white, ), child: Text( _iterations[index], style: TextStyle(fontSize: 12, fontFamily: 'Monospace'), ), ); }, ), ), ], ], ), ), ); } Widget _buildInputField(String label, String hint, TextEditingController controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: TextStyle(fontWeight: FontWeight.bold)), SizedBox(height: 4), TextField( controller: controller, decoration: InputDecoration( hintText: hint, border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), ), ], ); } }