diff --git a/Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs b/Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs index 346e1b318..6c63c030f 100644 --- a/Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs +++ b/Sources/Tests/DotnetBenchmark/CommonFunctionsInterVersion.cs @@ -76,6 +76,32 @@ [Benchmark] public void EvalTrigPrecise() private static readonly EContext fiveHundredDigits = new(500, ERounding.HalfUp, -500, 5000, false); + // Numerical evaluation of an expression at a point, which is what a plot or a + // root-finder asks for thousands of times: the expression is built once and the + // point substituted afresh on every call, so the per-node cost of the evaluation is + // what is measured and not the cache of a previous answer. A polynomial, for the + // arithmetic alone, and a logarithm times an arctangent, for the series behind the + // transcendental functions; the polynomial once more at fifteen digits, since how + // much of the cost is the width of the numbers and how much is the evaluator's own + // overhead is the question https://github.com/asc-community/AngouriMath/issues/1338 + // asks. The point is a decimal that is not within the downcasting tolerance of a + // small rational -- an exact `37/100` would be evaluated in rational arithmetic and + // never touch a decimal, and a binary double's fifty-three-digit expansion of 0.37 + // is not what anybody means by it. + [Benchmark] public void EvalPolynomialFresh() => evalPolynomial.Substitute(evalX, evalAt).EvalNumerical(); + [Benchmark] public void EvalTranscendentalFresh() => evalTranscendental.Substitute(evalX, evalAt).EvalNumerical(); + [Benchmark] public void EvalPolynomialFresh15Digits() + { + using var _ = MathS.Settings.DecimalPrecisionContext.Set(fifteenDigits); + evalPolynomial.Substitute(evalX, evalAt).EvalNumerical(); + } + private static readonly Entity.Variable evalX = MathS.Var("x"); + private static readonly Entity evalAt = Entity.Number.Real.Create(EDecimal.FromString("0.37000000000001234")); + private static readonly Entity evalPolynomial = "x^3 + 2*x^2 - x + 1"; + private static readonly Entity evalTranscendental = "ln(1 + x^2)*arctan(x)"; + private static readonly EContext fifteenDigits = + new(15, ERounding.HalfUp, -100, 1000, false); + // Testing compilation [Benchmark] public void CompileEasy() => toCompileEasy.Compile("x"); private static readonly Entity toCompileEasy = "x + x / 2 + sin(x)"; diff --git a/Sources/Tests/DotnetBenchmark/performance-baseline.json b/Sources/Tests/DotnetBenchmark/performance-baseline.json index def44be9e..416fb23a4 100644 --- a/Sources/Tests/DotnetBenchmark/performance-baseline.json +++ b/Sources/Tests/DotnetBenchmark/performance-baseline.json @@ -22,6 +22,18 @@ "allocatedBytes": 0, "meanNanoseconds": 1.8813217676555116 }, + "EvalPolynomialFresh": { + "allocatedBytes": 650888, + "meanNanoseconds": 348863.79150390625 + }, + "EvalPolynomialFresh15Digits": { + "allocatedBytes": 265816, + "meanNanoseconds": 83712.6138671875 + }, + "EvalTranscendentalFresh": { + "allocatedBytes": 5668395, + "meanNanoseconds": 3248098.8828125 + }, "EvalTrig": { "allocatedBytes": 1341457, "meanNanoseconds": 709052.2509114583