Skip to content

Commit 0c360a9

Browse files
committed
Add SIGMA accuracy test suite and CI verification step
1 parent 03d330a commit 0c360a9

3 files changed

Lines changed: 164 additions & 0 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ jobs:
125125
- name: Build with Gradle
126126
if: steps.check_changes.outputs.has_changes == 'true' || github.event.inputs.force_build == 'true'
127127
run: |
128+
gradle :core:testMath --no-daemon
128129
gradle clean shadowJar --no-daemon
129130
JAR_FILE=$(find plugin/build/libs -name "UltimateShop-*.jar" ! -name "*sources.jar" ! -name "*javadoc.jar" | head -1)
130131
if [ -n "$JAR_FILE" ]; then

core/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,10 @@ dependencies {
6060
compileOnly("de.oliver:FancyHolograms:2.9.1")
6161
implementation("cn.gtemc:itembridge:1.0.25")
6262
}
63+
64+
tasks.register<JavaExec>("testMath") {
65+
group = "verification"
66+
description = "Run EvalEx + SIGMA accuracy tests"
67+
mainClass.set("cn.superiormc.ultimateshop.utils.MathFunctionTest")
68+
classpath = sourceSets["main"].runtimeClasspath
69+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package cn.superiormc.ultimateshop.utils;
2+
3+
import com.ezylang.evalex.EvaluationException;
4+
import com.ezylang.evalex.Expression;
5+
import com.ezylang.evalex.config.ExpressionConfiguration;
6+
import com.ezylang.evalex.data.EvaluationValue;
7+
import com.ezylang.evalex.functions.AbstractFunction;
8+
import com.ezylang.evalex.functions.FunctionParameter;
9+
import com.ezylang.evalex.parser.Token;
10+
11+
import java.math.BigDecimal;
12+
import java.math.RoundingMode;
13+
14+
/**
15+
* 独立测试 EvalEx + SIGMA 自定义函数 —— 不依赖 ConfigManager
16+
* 运行: java -cp "build/classes;deps/*" cn.superiormc.ultimateshop.utils.MathFunctionTest
17+
*/
18+
public class MathFunctionTest {
19+
20+
private static final int SIGMA_MAX_ITERATIONS = 100000;
21+
private static final ExpressionConfiguration config;
22+
private static int passed;
23+
private static int failed;
24+
25+
static {
26+
config = ExpressionConfiguration.builder()
27+
.function("SIGMA", new SigmaFunction())
28+
.build();
29+
}
30+
31+
@FunctionParameter(name = "start")
32+
@FunctionParameter(name = "end")
33+
@FunctionParameter(name = "body")
34+
public static class SigmaFunction extends AbstractFunction {
35+
@Override
36+
public EvaluationValue evaluate(EvaluationValue... args) {
37+
int start = args[0].getNumberValue().intValue();
38+
int end = args[1].getNumberValue().intValue();
39+
String body = args[2].getStringValue();
40+
if (start > end) return EvaluationValue.numberValue(BigDecimal.ZERO);
41+
int count = end - start + 1;
42+
if (count > SIGMA_MAX_ITERATIONS) {
43+
throw new EvaluationException(new Token(0, body),
44+
"SIGMA: too many iterations (" + count + ")");
45+
}
46+
BigDecimal sum = BigDecimal.ZERO;
47+
for (int i = start; i <= end; i++) {
48+
Expression sub = new Expression(body, config).with("i", BigDecimal.valueOf(i));
49+
sum = sum.add(sub.evaluate().getNumberValue());
50+
}
51+
return EvaluationValue.numberValue(sum);
52+
}
53+
}
54+
55+
static BigDecimal calc(String expr) {
56+
return new Expression(expr, config).evaluate().getNumberValue()
57+
.setScale(10, RoundingMode.HALF_UP).stripTrailingZeros();
58+
}
59+
60+
static void check(String name, String expr, BigDecimal expected) {
61+
try {
62+
BigDecimal result = calc(expr);
63+
if (result.compareTo(expected) == 0) {
64+
passed++;
65+
System.out.println(" PASS: " + name + " = " + result);
66+
} else {
67+
failed++;
68+
System.out.println(" FAIL: " + name);
69+
System.out.println(" expected: " + expected);
70+
System.out.println(" got : " + result);
71+
}
72+
} catch (Exception e) {
73+
failed++;
74+
System.out.println(" FAIL: " + name + " (threw " + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
75+
}
76+
}
77+
78+
static BigDecimal d(String s) { return new BigDecimal(s); }
79+
80+
public static void main(String[] args) {
81+
System.out.println("= EvalEx + SIGMA 自定义函数 准确性测试 =\n");
82+
83+
System.out.println("--- 基础四则运算 ---");
84+
check("1+1", "1+1", d("2"));
85+
check("3*4", "3*4", d("12"));
86+
check("10/3", "10/3", d("3.3333333333"));
87+
check("2^10", "2^10", d("1024"));
88+
check("(1+2)*3", "(1+2)*3", d("9"));
89+
check("10%3", "10%3", d("1"));
90+
check("-5+8", "-5+8", d("3"));
91+
check("2.5*4", "2.5*4", d("10"));
92+
check("隐式乘法 2(3+4)", "2(3+4)", d("14"));
93+
94+
System.out.println("\n--- 内置数学函数 ---");
95+
check("SQRT(16)", "SQRT(16)", d("4"));
96+
check("SQRT(2)", "SQRT(2)", d("1.4142135624"));
97+
check("ABS(-5)", "ABS(-5)", d("5"));
98+
check("ROUND(3.14159, 2)", "ROUND(3.14159, 2)", d("3.14"));
99+
check("FLOOR(3.9)", "FLOOR(3.9)", d("3"));
100+
check("CEILING(3.1)", "CEILING(3.1)", d("4"));
101+
check("LOG(2.718281828)", "LOG(2.718281828)", d("0.9999999993"));
102+
check("LOG10(100)", "LOG10(100)", d("2"));
103+
check("SIN(0)", "SIN(0)", d("0"));
104+
check("COS(0)", "COS(0)", d("1"));
105+
check("TAN(0)", "TAN(0)", d("0"));
106+
check("EXP(1)", "EXP(1)", d("2.7182818285"));
107+
check("FACT(5)", "FACT(5)", d("120"));
108+
check("MIN(3, 1, 4, 2)", "MIN(3, 1, 4, 2)", d("1"));
109+
check("MAX(3, 1, 4, 2)", "MAX(3, 1, 4, 2)", d("4"));
110+
111+
System.out.println("\n--- 布尔表达式 ---");
112+
check("1>0", "IF(1>0, 100, 0)", d("100"));
113+
check("1==1", "IF(1==1, 200, 0)", d("200"));
114+
check("1!=2", "IF(1!=2, 300, 0)", d("300"));
115+
check("AND", "IF(1<2 AND 2<3, 400, 0)", d("400"));
116+
check("OR", "IF(1>2 OR 2<3, 500, 0)", d("500"));
117+
check("NOT", "IF(NOT(1>2), 600, 0)", d("600"));
118+
119+
System.out.println("\n--- SIGMA 求和 ---");
120+
check("SIGMA(1, 10, \"i\") Σi", "SIGMA(1, 10, \"i\")", d("55"));
121+
check("SIGMA(1, 10, \"i*i\") Σi²", "SIGMA(1, 10, \"i*i\")", d("385"));
122+
check("SIGMA(1, 5, \"i^3\") Σi³", "SIGMA(1, 5, \"i^3\")", d("225"));
123+
check("SIGMA(1, 100, \"1\") counting","SIGMA(1, 100, \"1\")", d("100"));
124+
check("SIGMA(1, 4, \"FACT(i)\") Σi!", "SIGMA(1, 4, \"FACT(i)\")", d("33"));
125+
check("SIGMA(1, 1, \"42\") 单次", "SIGMA(1, 1, \"42\")", d("42"));
126+
check("SIGMA(0, 0, \"99\") 零索引", "SIGMA(0, 0, \"99\")", d("99"));
127+
check("SIGMA(5, 1, \"i\") start>end","SIGMA(5, 1, \"i\")", d("0"));
128+
129+
System.out.println("\n--- SIGMA 边界/嵌套 ---");
130+
check("SIGMA with EXP", "SIGMA(1, 5, \"EXP(-0.1*i)\")",
131+
d("4.4959131450"));
132+
check("SIGMA with SQRT", "SIGMA(1, 9, \"SQRT(i)\")",
133+
d("19.3060005260"));
134+
check("嵌套 IF", "SIGMA(1, 10, \"IF(i%2==0, i, 0)\")",
135+
d("30"));
136+
check("大范围 sigma", "SIGMA(1, 1000, \"1\")",
137+
d("1000"));
138+
139+
System.out.println("\n--- 文章中的实用公式 ---");
140+
check("e^{-lambda*n} λ=0.1 n=10", "EXP(-0.1*10)", d("0.3678794412"));
141+
check("round{x, 2}", "ROUND(3.14159, 2)", d("3.14"));
142+
check("floor{x}", "FLOOR(3.9)", d("3"));
143+
check("1-e^{-λn} λ=0.1 n=5", "1-EXP(-0.1*5)", d("0.3934693403"));
144+
check("(t-μ)^6/(2σ²) t=10 μ=5 σ=2","(10-5)^6/(2*2^2)", d("1953.125"));
145+
check("exp[-(t-μ)^6/(2σ²)]", "EXP(-(10-5)^6/(2*2^2))", d("0.0000000000"));
146+
147+
System.out.println("\n" + "=".repeat(40));
148+
System.out.println("总计: " + (passed + failed) + " 项, 通过 " + passed + ", 失败 " + failed);
149+
if (failed > 0) {
150+
System.out.println(" 存在失败用例!");
151+
System.exit(1);
152+
} else {
153+
System.out.println(" 全部通过!");
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)