✨ Percentage
This commit is contained in:
@@ -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;
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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");
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user