| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- /* 此文件实现了有理数与二次根式形成的数域
- * 需要在pubspec.yaml中添加依赖rational: ^2.2.3
- * 使用方法请看最后的测试用例
- * Ksqrt类表示有理数乘以根号整数
- * RationalExtend类表示多个Ksqrt类根式相加
- * Author:nonvioce
- * Time: 2025.10.26
- */
- import 'package:rational/rational.dart';
- import 'dart:math';
- class Ksqrt {
- Rational k; // 有理数系数
- int q; // 底数(整数)
- Ksqrt(this.k, this.q) {
- if (q < 0) throw ArgumentError("底数q不能为负数");
- }
- // 从整数创建(系数为整数,底数为1)
- factory Ksqrt.fromInt(int value) {
- return Ksqrt(Rational.fromInt(value), 1);
- }
- // 从Rational创建(系数为有理数,底数为1)
- factory Ksqrt.fromRational(Rational rational) {
- return Ksqrt(rational, 1);
- }
- // 增强的字符串解析 - 增加小数支持
- factory Ksqrt.parse(String str) {
- str = str.trim();
- // 处理纯数字(整数或小数)
- if (RegExp(r'^-?\d+(\.\d+)?$').hasMatch(str)) {
- return Ksqrt.fromRational(_parseRational(str));
- }
- // 处理分数(不包含根号)
- if (str.contains('/') && !str.contains('√')) {
- try {
- var parts = str.split('/');
- if (parts.length != 2) throw FormatException("无效的分数格式: $str");
- var numerator = _parseRational(parts[0]);
- var denominator = _parseRational(parts[1]);
- if (denominator == Rational.zero) throw FormatException("分母不能为零: $str");
- return Ksqrt.fromRational(numerator / denominator);
- } catch (e) {
- throw FormatException("无效的分数格式: $str, 错误: $e");
- }
- }
- // 处理根式
- if (str.contains('√')) {
- var sqrtIndex = str.indexOf('√');
- var coefficientStr = str.substring(0, sqrtIndex);
- var radicandStr = str.substring(sqrtIndex + 1);
- // 处理括号内的底数
- if (radicandStr.startsWith('(') && radicandStr.endsWith(')')) {
- radicandStr = radicandStr.substring(1, radicandStr.length - 1);
- }
- Rational k;
- // 解析系数
- if (coefficientStr.isEmpty || coefficientStr == "+") {
- k = Rational.one;
- } else if (coefficientStr == "-") {
- k = -Rational.one;
- } else {
- coefficientStr = coefficientStr.replaceAll('*', '');
- try {
- if (coefficientStr.contains('/')) {
- var coeffParts = coefficientStr.split('/');
- if (coeffParts.length != 2) throw FormatException("无效的系数格式: $coefficientStr");
- var num = _parseRational(coeffParts[0]);
- var den = _parseRational(coeffParts[1]);
- if (den == Rational.zero) throw FormatException("分母不能为零: $coefficientStr");
- k = num / den;
- } else {
- k = _parseRational(coefficientStr);
- }
- } catch (e) {
- throw FormatException("无效的系数格式: $coefficientStr");
- }
- }
- // 解析底数
- int q;
- if (radicandStr.contains('/')) {
- throw FormatException("分数底数暂不支持: $str");
- } else {
- try {
- // 底数必须是整数,所以使用int.parse而不是_parseRational
- q = int.parse(radicandStr);
- } catch (e) {
- throw FormatException("无效的底数格式: $radicandStr");
- }
- }
- return Ksqrt(k, q)..simplify();
- }
- // 尝试解析为有理数(包括小数)
- try {
- return Ksqrt.fromRational(_parseRational(str));
- } catch (e) {
- throw FormatException("无法解析的字符串: $str");
- }
- }
- // 小数转有理数的辅助函数
- static Rational _parseRational(String input) {
- try {
- input = input.trim();
- if (input.contains('/')) {
- List<String> parts = input.split('/');
- if (parts.length == 2) {
- String numerator = parts[0].trim();
- String denominator = parts[1].trim();
- // 修复:直接使用 Rational 构造函数而不是 parse
- BigInt num = BigInt.parse(numerator);
- BigInt den = BigInt.parse(denominator);
- if (den == BigInt.zero) {
- throw FormatException('分母不能为零');
- }
- return Rational(num, den);
- }
- }
- // 处理小数
- if (input.contains('.')) {
- return _decimalToRational(input);
- }
- // 处理整数
- return Rational.parse(input);
- } catch (e) {
- throw FormatException('无效的分数格式: $input');
- }
- }
- // 小数转有理数的实现
- static Rational _decimalToRational(String decimalStr) {
- if (!decimalStr.contains('.')) {
- return Rational.parse(decimalStr);
- }
- List<String> parts = decimalStr.split('.');
- String integerPart = parts[0];
- String decimalPart = parts[1];
- // 处理负号
- bool isNegative = integerPart.startsWith('-');
- if (isNegative) {
- integerPart = integerPart.substring(1);
- }
- // 如果整数部分是空的,设为0
- if (integerPart.isEmpty) {
- integerPart = '0';
- }
- // 计算分母:10的decimalPart长度次方
- BigInt denominator = BigInt.from(10).pow(decimalPart.length);
- // 计算分子:整数部分 * 分母 + 小数部分
- BigInt numerator =
- BigInt.parse(integerPart) * denominator + BigInt.parse(decimalPart);
- if (isNegative) {
- numerator = -numerator;
- }
- return Rational(numerator, denominator);
- }
- // 取反运算
- Ksqrt operator -() {
- return Ksqrt(-k, q);
- }
- // 修复的化简方法
- void simplify() {
- if (k == Rational.zero) {
- q = 1;
- return;
- }
- if (q == 0 || q == 1) return;
- // 提取平方因子
- int squareFactor = 1;
- int temp = q;
- for (int i = 2; i * i <= temp; i++) {
- while (temp % (i * i) == 0) {
- squareFactor *= i;
- temp ~/= (i * i);
- }
- }
- // 更新系数和底数
- if (squareFactor > 1) {
- k *= Rational.fromInt(squareFactor);
- q = temp;
- }
- }
- // 判断两个Ksqrt是否同类项
- bool isLikeTerm(Ksqrt other) {
- Ksqrt thisCopy = Ksqrt(k, q);
- Ksqrt otherCopy = Ksqrt(other.k, other.q);
- thisCopy.simplify();
- otherCopy.simplify();
- return thisCopy.q == otherCopy.q;
- }
- // 加法运算
- Ksqrt operator +(Ksqrt other) {
- if (!isLikeTerm(other)) {
- throw ArgumentError("底数不同无法相加: ${this.q} 和 ${other.q}");
- }
- Ksqrt thisCopy = Ksqrt(k, q);
- Ksqrt otherCopy = Ksqrt(other.k, other.q);
- thisCopy.simplify();
- otherCopy.simplify();
- return Ksqrt(thisCopy.k + otherCopy.k, thisCopy.q);
- }
- // 减法运算
- Ksqrt operator -(Ksqrt other) {
- if (!isLikeTerm(other)) {
- throw ArgumentError("底数不同无法相减: ${this.q} 和 ${other.q}");
- }
- Ksqrt thisCopy = Ksqrt(k, q);
- Ksqrt otherCopy = Ksqrt(other.k, other.q);
- thisCopy.simplify();
- otherCopy.simplify();
- return Ksqrt(thisCopy.k - otherCopy.k, thisCopy.q);
- }
- // 乘法运算
- Ksqrt operator *(Ksqrt other) {
- Rational newK = k * other.k;
- int newQ = q * other.q;
- Ksqrt result = Ksqrt(newK, newQ);
- result.simplify();
- return result;
- }
- // 修复的除法运算
- Ksqrt operator /(Ksqrt other) {
- if (other.k == Rational.zero) {
- throw ArgumentError("除数不能为零");
- }
- // 分子分母同乘以分母的根号部分进行有理化
- Rational newK = k * other.k;
- int newQ = q * other.q;
- // 除以分母系数的平方(因为分母是k√q,有理化后分母变为k²q)
- Rational denominator = other.k * other.k * Rational.fromInt(other.q);
- Ksqrt result = Ksqrt(newK / denominator, newQ);
- result.simplify();
- return result;
- }
- @override
- bool operator ==(Object other) {
- if (identical(this, other)) return true;
- if (other is! Ksqrt) return false;
- Ksqrt thisSimplified = Ksqrt(k, q)..simplify();
- Ksqrt otherSimplified = Ksqrt(other.k, other.q)..simplify();
- return thisSimplified.k == otherSimplified.k &&
- thisSimplified.q == otherSimplified.q;
- }
- @override
- int get hashCode {
- Ksqrt simplified = Ksqrt(k, q)..simplify();
- return Object.hash(simplified.k, simplified.q);
- }
- // 计算表达式的近似浮点数值
- double toDouble() {
- if (k == Rational.zero) return 0.0;
- double sqrtQ = sqrt(q.toDouble());
- double kValue = k.toDouble();
- return kValue * sqrtQ;
- }
- @override
- String toString() {
- if (k == Rational.zero) return '0';
- if (q == 1) return k.toString();
- String kStr;
- if (k == Rational.one) {
- kStr = '';
- } else if (k == -Rational.one) {
- kStr = '-';
- } else {
- if (k.isInteger) {
- kStr = k.toDouble().toInt().toString();
- } else {
- kStr = '($k)';
- }
- kStr += '*';
- }
- return '${kStr}√$q';
- }
- }
- class RationalExtend {
- List<Ksqrt> terms;
- RationalExtend(this.terms);
- factory RationalExtend.fromInt(int value) {
- return RationalExtend([Ksqrt.fromInt(value)]);
- }
- factory RationalExtend.fromRational(Rational rational) {
- return RationalExtend([Ksqrt.fromRational(rational)]);
- }
- // 改进的字符串解析 - 现在支持小数
- factory RationalExtend.parse(String str) {
- str = str.replaceAll(' ', '');
- if (str.isEmpty) return RationalExtend([]);
- // 处理单个项的情况
- if (!str.contains('+') && !str.contains('-')) {
- return RationalExtend([Ksqrt.parse(str)]);
- }
- // 处理以负号开头的情况
- if (str.startsWith('-')) {
- var rest = str.substring(1);
- if (!rest.contains('+') && !rest.contains('-')) {
- return RationalExtend([Ksqrt.parse(str)]);
- }
- }
- List<Ksqrt> terms = [];
- List<String> termStrs = [];
- // 改进的分割逻辑:正确处理符号
- int start = 0;
- for (int i = 1; i < str.length; i++) {
- if ((str[i] == '+' || str[i] == '-') &&
- str[i-1] != '*' && str[i-1] != '/' && str[i-1] != '^') {
- termStrs.add(str.substring(start, i));
- start = i;
- }
- }
- termStrs.add(str.substring(start));
- // 解析各项
- for (var termStr in termStrs) {
- if (termStr.isEmpty) continue;
- if (termStr == '+') continue;
- try {
- terms.add(Ksqrt.parse(termStr));
- } catch (e) {
- throw FormatException("无法解析项: $termStr, 错误: $e");
- }
- }
- return RationalExtend(terms)..simplify();
- }
- void addTerm(Ksqrt term) {
- terms.add(term);
- }
- // 化简方法:合并同类项
- void simplify() {
- if (terms.isEmpty) return;
- // 首先对每个项进行化简
- for (var term in terms) {
- term.simplify();
- }
- // 合并同类项
- Map<int, Rational> termMap = {};
- for (var term in terms) {
- if (termMap.containsKey(term.q)) {
- termMap[term.q] = termMap[term.q]! + term.k;
- } else {
- termMap[term.q] = term.k;
- }
- }
- // 重建terms列表
- terms.clear();
- termMap.forEach((q, k) {
- if (k != Rational.zero) {
- terms.add(Ksqrt(k, q));
- }
- });
- // 按底数排序
- terms.sort((a, b) => a.q.compareTo(b.q));
- if (terms.isEmpty) {
- terms.add(Ksqrt.fromInt(0));
- }
- }
- // 获取共轭表达式
- RationalExtend get conjugate {
- if (terms.length == 1) {
- return RationalExtend([terms[0]]);
- } else if (terms.length == 2) {
- return RationalExtend([
- terms[0],
- Ksqrt(-terms[1].k, terms[1].q)
- ]);
- } else {
- List<Ksqrt> conjugateTerms = [terms[0]];
- for (int i = 1; i < terms.length; i++) {
- conjugateTerms.add(Ksqrt(-terms[i].k, terms[i].q));
- }
- return RationalExtend(conjugateTerms);
- }
- }
- // 检查是否是有理数
- bool get isRational {
- for (var term in terms) {
- if (term.q != 1) return false;
- }
- return true;
- }
- // 获取有理数部分的值
- Rational get rationalValue {
- if (!isRational) {
- throw StateError("表达式包含根号,不是纯有理数");
- }
- Rational sum = Rational.zero;
- for (var term in terms) {
- sum += term.k;
- }
- return sum;
- }
- // 加法运算
- RationalExtend operator +(RationalExtend other) {
- List<Ksqrt> newTerms = List.from(terms);
- newTerms.addAll(other.terms);
- RationalExtend result = RationalExtend(newTerms);
- result.simplify();
- return result;
- }
- // 减法运算
- RationalExtend operator -(RationalExtend other) {
- List<Ksqrt> newTerms = List.from(terms);
- for (var term in other.terms) {
- newTerms.add(Ksqrt(-term.k, term.q));
- }
- RationalExtend result = RationalExtend(newTerms);
- result.simplify();
- return result;
- }
- // 乘法运算
- RationalExtend operator *(RationalExtend other) {
- List<Ksqrt> productTerms = [];
- for (var term1 in terms) {
- for (var term2 in other.terms) {
- productTerms.add(term1 * term2);
- }
- }
- RationalExtend result = RationalExtend(productTerms);
- result.simplify();
- return result;
- }
- // 修复的除法运算
- RationalExtend operator /(RationalExtend other) {
- if (other.terms.isEmpty) {
- throw ArgumentError("除数不能为空");
- }
- // 特殊情况:除数是单项式
- if (other.terms.length == 1) {
- List<Ksqrt> newTerms = [];
- for (var term in terms) {
- newTerms.add(term / other.terms[0]);
- }
- return RationalExtend(newTerms)..simplify();
- }
- // 一般情况:使用分母有理化
- RationalExtend conjugate = other.conjugate;
- RationalExtend numerator = this * conjugate;
- RationalExtend denominator = other * conjugate;
- if (!denominator.isRational) {
- throw StateError("分母有理化失败,结果仍包含根号");
- }
- Rational denomValue = denominator.rationalValue;
- if (denomValue == Rational.zero) {
- throw ArgumentError("分母有理化后为0,无法进行除法");
- }
- // 将分子中的每一项除以分母的有理数值
- List<Ksqrt> resultTerms = [];
- for (var term in numerator.terms) {
- resultTerms.add(Ksqrt(term.k / denomValue, term.q));
- }
- return RationalExtend(resultTerms)..simplify();
- }
- @override
- bool operator ==(Object other) {
- if (identical(this, other)) return true;
- if (other is! RationalExtend) return false;
- RationalExtend thisSimplified = RationalExtend(List.from(terms))..simplify();
- RationalExtend otherSimplified = RationalExtend(List.from(other.terms))..simplify();
- if (thisSimplified.terms.length != otherSimplified.terms.length) return false;
- for (int i = 0; i < thisSimplified.terms.length; i++) {
- if (thisSimplified.terms[i] != otherSimplified.terms[i]) {
- return false;
- }
- }
- return true;
- }
- @override
- int get hashCode {
- RationalExtend simplified = RationalExtend(List.from(terms))..simplify();
- return simplified.terms.fold(0, (hash, term) => hash ^ term.hashCode);
- }
- // 计算表达式的近似浮点数值
- double toDouble() {
- double sum = 0.0;
- for (var term in terms) {
- sum += term.toDouble();
- }
- return sum;
- }
- @override
- String toString() {
- if (terms.isEmpty) return "0";
- RationalExtend simplified = RationalExtend(List.from(terms))..simplify();
- if (simplified.terms.isEmpty) return "0";
- List<String> termStrings = [];
- for (var term in simplified.terms) {
- String termStr = term.toString();
- if (termStr.startsWith('-')) {
- termStrings.add(termStr);
- } else if (termStrings.isNotEmpty) {
- termStrings.add('+$termStr');
- } else {
- termStrings.add(termStr);
- }
- }
- String result = termStrings.join('');
- if (result.startsWith('+')) {
- result = result.substring(1);
- }
- return result;
- }
- }
- extension RationalExtendMath on RationalExtend {
- RationalExtend square() {
- return this * this;
- }
- RationalExtend abs() {
- double value = this.toDouble();
- if (value < 0) {
- return RationalExtend(terms.map((term) => Ksqrt(-term.k, term.q)).toList());
- }
- return this;
- }
- bool get isZero {
- RationalExtend simplified = RationalExtend(List.from(terms))..simplify();
- return simplified.terms.length == 1 &&
- simplified.terms[0].k == Rational.zero;
- }
- Rational get rationalPart {
- Rational sum = Rational.zero;
- for (var term in terms) {
- if (term.q == 1) {
- sum += term.k;
- }
- }
- return sum;
- }
- RationalExtend get irrationalPart {
- List<Ksqrt> irrationalTerms = [];
- for (var term in terms) {
- if (term.q != 1) {
- irrationalTerms.add(term);
- }
- }
- return RationalExtend(irrationalTerms)..simplify();
- }
- }
- /*测试用例
- // 测试函数 - 增加小数测试
- void main() {
- print('=== Ksqrt 类测试 ===');
- // 基本创建和化简
- var sqrt8 = Ksqrt(Rational.one, 8);
- sqrt8.simplify();
- print('√8 = $sqrt8'); // 应该输出 2√2
- // 算术运算
- var a = Ksqrt.parse('√2');
- var b = Ksqrt.parse('3√2');
- var sum = a + b;
- print('√2 + 3√2 = $sum'); // 应该输出 4√2
- var product = a * b;
- print('√2 * 3√2 = $product'); // 应该输出 6
- // 除法测试 - 修复后
- var c = Ksqrt.parse('√6');
- var d = Ksqrt.parse('√3');
- var quotient = c / d;
- print('√6 / √3 = $quotient'); // 应该输出 √2
- print('\n=== RationalExtend 类测试 ===');
- // 多项式创建和运算
- var expr1 = RationalExtend.parse('√2 + 2√3');
- var expr2 = RationalExtend.parse('√2 - √3');
- print('表达式1: $expr1');
- print('表达式2: $expr2');
- var polySum = expr1 + expr2;
- print('相加: $polySum'); // 应该输出 2√2 + √3
- var polyProduct = expr1 * expr2;
- print('相乘: $polyProduct'); // 应该输出 2 + √6 - 2√3 - 2*3 = -4 + √6 - 2√3
- // 除法测试(分母有理化)- 修复后
- try {
- var polyQuotient = expr1 / expr2;
- print('相除: $polyQuotient'); // 应该输出有理化后的结果
- } catch (e) {
- print('除法错误: $e');
- }
- // 复杂表达式测试
- print('\n=== 复杂表达式测试 ===');
- try {
- var complexExpr = RationalExtend.parse('2/3');
- print('分数解析: $complexExpr');
- var complexExpr2 = RationalExtend.parse('2/3+√2');
- print('分数+根号解析: $complexExpr2');
- var complexExpr3 = RationalExtend.parse('1+√2');
- var mul = complexExpr2 * complexExpr3;
- print('复杂表达式1: $complexExpr2');
- print('复杂表达式2: $complexExpr3');
- print('乘积: $mul');
- print('有理数部分: ${complexExpr2.rationalPart}');
- print('无理数部分: ${complexExpr2.irrationalPart}');
- print('近似值: ${complexExpr2.toDouble()}');
- } catch (e) {
- print('解析错误: $e');
- }
- // 更多测试
- print('\n=== 更多测试 ===');
- try {
- var test1 = Ksqrt.parse('1/2');
- print('分数 1/2: $test1');
- var test2 = Ksqrt.parse('3/4*√2');
- print('分数系数 3/4*√2: $test2');
- var test3 = RationalExtend.parse('1/2 + 1/3*√2');
- print('混合表达式: $test3');
- } catch (e) {
- print('测试错误: $e');
- }
- // 小数测试
- print('\n=== 小数支持测试 ===');
- try {
- var decimal1 = Ksqrt.parse('0.5');
- print('小数 0.5: $decimal1');
- var decimal2 = Ksqrt.parse('0.25√2');
- print('小数系数 0.25√2: $decimal2');
- var decimal3 = Ksqrt.parse('1.5√3');
- print('小数系数 1.5√3: $decimal3');
- var decimal4 = RationalExtend.parse('0.5 + 3/2√2');
- print('混合小数表达式: $decimal4');
- var decimal5 = RationalExtend.parse('1/3 + 0.666√2');
- print('混合小数表达式: $decimal5');
- // 小数运算测试
- var decimalExpr1 = RationalExtend.parse('0.5√2');
- var decimalExpr2 = RationalExtend.parse('0.25√2');
- var decimalSum = decimalExpr1 + decimalExpr2;
- print('0.5√2 + 0.25√2 = $decimalSum'); // 应该输出 0.75√2
- var decimalProduct = decimalExpr1 * decimalExpr2;
- print('0.5√2 * 0.25√2 = $decimalProduct'); // 应该输出 0.25
- } catch (e) {
- print('小数测试错误: $e');
- }
- }
- */
|