Percentage

This commit is contained in:
2025-09-14 14:13:14 +08:00
parent 6590c33732
commit 5cf66cd1f2
3 changed files with 147 additions and 1 deletions

View File

@@ -151,6 +151,17 @@ class AddExpr extends Expr {
return IntExpr(l.value + r.value); return IntExpr(l.value + r.value);
} }
// 小数相加
if (l is DoubleExpr && r is DoubleExpr) {
return DoubleExpr(l.value + r.value);
}
if (l is IntExpr && r is DoubleExpr) {
return DoubleExpr(l.value + r.value);
}
if (l is DoubleExpr && r is IntExpr) {
return DoubleExpr(l.value + r.value);
}
// 分数相加 / 分数与整数相加 // 分数相加 / 分数与整数相加
if (l is FractionExpr && r is FractionExpr) { if (l is FractionExpr && r is FractionExpr) {
return FractionExpr( return FractionExpr(
@@ -171,6 +182,14 @@ class AddExpr extends Expr {
).simplify(); ).simplify();
} }
// 分数与小数相加
if (l is FractionExpr && r is DoubleExpr) {
return DoubleExpr(l.numerator / l.denominator + r.value);
}
if (l is DoubleExpr && r is FractionExpr) {
return DoubleExpr(l.value + r.numerator / r.denominator);
}
// 合并同类的 sqrt 项: a*sqrt(X) + b*sqrt(X) = (a+b)*sqrt(X) // 合并同类的 sqrt 项: a*sqrt(X) + b*sqrt(X) = (a+b)*sqrt(X)
var a = _asSqrtTerm(l); var a = _asSqrtTerm(l);
var b = _asSqrtTerm(r); var b = _asSqrtTerm(r);
@@ -221,6 +240,18 @@ class SubExpr extends Expr {
if (l is IntExpr && r is IntExpr) { if (l is IntExpr && r is IntExpr) {
return IntExpr(l.value - r.value); return IntExpr(l.value - r.value);
} }
// 小数相减
if (l is DoubleExpr && r is DoubleExpr) {
return DoubleExpr(l.value - r.value);
}
if (l is IntExpr && r is DoubleExpr) {
return DoubleExpr(l.value - r.value);
}
if (l is DoubleExpr && r is IntExpr) {
return DoubleExpr(l.value - r.value);
}
if (l is FractionExpr && r is FractionExpr) { if (l is FractionExpr && r is FractionExpr) {
return FractionExpr( return FractionExpr(
l.numerator * r.denominator - r.numerator * l.denominator, l.numerator * r.denominator - r.numerator * l.denominator,
@@ -240,6 +271,14 @@ class SubExpr extends Expr {
).simplify(); ).simplify();
} }
// 分数与小数相减
if (l is FractionExpr && r is DoubleExpr) {
return DoubleExpr(l.numerator / l.denominator - r.value);
}
if (l is DoubleExpr && r is FractionExpr) {
return DoubleExpr(l.value - r.numerator / r.denominator);
}
// 处理同类 sqrt 项: a*sqrt(X) - b*sqrt(X) = (a-b)*sqrt(X) // 处理同类 sqrt 项: a*sqrt(X) - b*sqrt(X) = (a-b)*sqrt(X)
var a = _asSqrtTerm(l); var a = _asSqrtTerm(l);
var b = _asSqrtTerm(r); var b = _asSqrtTerm(r);
@@ -311,6 +350,18 @@ class MulExpr extends Expr {
if (l is IntExpr && r is IntExpr) { if (l is IntExpr && r is IntExpr) {
return IntExpr(l.value * r.value); return IntExpr(l.value * r.value);
} }
// 小数相乘
if (l is DoubleExpr && r is DoubleExpr) {
return DoubleExpr(l.value * r.value);
}
if (l is IntExpr && r is DoubleExpr) {
return DoubleExpr(l.value * r.value);
}
if (l is DoubleExpr && r is IntExpr) {
return DoubleExpr(l.value * r.value);
}
if (l is FractionExpr && r is IntExpr) { if (l is FractionExpr && r is IntExpr) {
return FractionExpr(l.numerator * r.value, l.denominator).simplify(); return FractionExpr(l.numerator * r.value, l.denominator).simplify();
} }
@@ -324,6 +375,14 @@ class MulExpr extends Expr {
).simplify(); ).simplify();
} }
// 分数与小数相乘
if (l is FractionExpr && r is DoubleExpr) {
return DoubleExpr(l.numerator / l.denominator * r.value);
}
if (l is DoubleExpr && r is FractionExpr) {
return DoubleExpr(l.value * r.numerator / r.denominator);
}
// sqrt * sqrt: sqrt(a)*sqrt(a) = a // sqrt * sqrt: sqrt(a)*sqrt(a) = a
if (l is SqrtExpr && if (l is SqrtExpr &&
r is SqrtExpr && r is SqrtExpr &&
@@ -856,6 +915,37 @@ class AbsExpr extends Expr {
String toString() => "|$inner|"; String toString() => "|$inner|";
} }
// === PercentExpr ===
class PercentExpr extends Expr {
final Expr inner;
PercentExpr(this.inner);
@override
Expr simplify() => PercentExpr(inner.simplify());
@override
Expr evaluate() {
var i = inner.evaluate();
if (i is IntExpr) {
return DoubleExpr(i.value / 100.0);
}
if (i is DoubleExpr) {
return DoubleExpr(i.value / 100.0);
}
if (i is FractionExpr) {
return DoubleExpr(i.numerator / (i.denominator * 100.0));
}
return PercentExpr(i);
}
@override
Expr substitute(String varName, Expr value) =>
PercentExpr(inner.substitute(varName, value));
@override
String toString() => "$inner%";
}
// === 辅助:识别 a * sqrt(X) 形式 === // === 辅助:识别 a * sqrt(X) 形式 ===
class _SqrtTerm { class _SqrtTerm {
final int coef; final int coef;

View File

@@ -17,7 +17,15 @@ class Parser {
} }
} }
Expr parse() => parseAdd(); Expr parse() {
var expr = parseAdd();
skipSpaces();
if (!isEnd && current == '%') {
eat();
expr = PercentExpr(expr);
}
return expr;
}
Expr parseAdd() { Expr parseAdd() {
var expr = parseMul(); var expr = parseMul();
@@ -46,6 +54,12 @@ class Parser {
} }
skipSpaces(); skipSpaces();
} }
// Handle percentage operator
skipSpaces();
if (!isEnd && current == '%') {
eat();
expr = PercentExpr(expr);
}
return expr; return expr;
} }

View File

@@ -231,4 +231,46 @@ void main() {
); );
}); });
}); });
group('百分比运算符', () {
test('基本百分比', () {
var expr = Parser("50%").parse();
expect(expr.evaluate().toString(), "0.5");
});
test('100%', () {
var expr = Parser("100%").parse();
expect(expr.evaluate().toString(), "1.0");
});
test('25%', () {
var expr = Parser("25%").parse();
expect(expr.evaluate().toString(), "0.25");
});
test('负百分比', () {
var expr = Parser("-50%").parse();
expect(expr.evaluate().toString(), "-0.5");
});
test('小数百分比', () {
var expr = Parser("50.5%").parse();
expect(expr.evaluate().toString(), "0.505");
});
test('分数百分比', () {
var expr = Parser("1/2%").parse();
expect(expr.evaluate().toString(), "0.005");
});
test('百分比在表达式中', () {
var expr = Parser("50% + 25%").parse();
expect(expr.evaluate().toString(), "0.75");
});
test('百分比与数字相乘', () {
var expr = Parser("2 * 50%").parse();
expect(expr.evaluate().toString(), "1.0");
});
});
} }