|
| 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