diff --git a/Sources/AngouriMath/Numerics/IntervalEvaluation.cs b/Sources/AngouriMath/Numerics/IntervalEvaluation.cs index c5cb48499..50e74cf58 100644 --- a/Sources/AngouriMath/Numerics/IntervalEvaluation.cs +++ b/Sources/AngouriMath/Numerics/IntervalEvaluation.cs @@ -324,16 +324,16 @@ internal static class IntervalEvaluation [AngouriMath.Core.ConstantField] private static readonly ComplexInterval Undefined = new(new(double.NaN, double.NaN), new(double.NaN, double.NaN)); + /// + /// The arithmetic is what nests deep -- a sum of a few hundred terms is a few hundred + /// frames -- so it is kept apart from the other arms, whose temporaries and closures would + /// otherwise widen every one of those frames: with them in one method, 228 nested sums + /// overflowed a 1 MB stack. + /// private static ComplexInterval Evaluate(Entity expr) { switch (expr) { - case Number.Complex number: - return FromNumber(number); - case Variable variable when variable == MathS.pi: - return ComplexInterval.Real(Interval.Around(Math.PI)); - case Variable variable when variable == MathS.e: - return ComplexInterval.Real(Interval.Around(Math.E)); case Sumf(var left, var right): return Evaluate(left) + Evaluate(right); case Minusf(var left, var right): @@ -345,6 +345,22 @@ private static ComplexInterval Evaluate(Entity expr) // In the range of an int, so that the reciprocal's negation cannot overflow. case Powf(var @base, Number.Integer power) when power.EInteger.CanFitInInt32(): return Evaluate(@base).Pow(power.EInteger.ToInt32Checked()); + default: + return EvaluateOtherThanArithmetic(expr); + } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + private static ComplexInterval EvaluateOtherThanArithmetic(Entity expr) + { + switch (expr) + { + case Number.Complex number: + return FromNumber(number); + case Variable variable when variable == MathS.pi: + return ComplexInterval.Real(Interval.Around(Math.PI)); + case Variable variable when variable == MathS.e: + return ComplexInterval.Real(Interval.Around(Math.E)); case Powf(var @base, var exponent): if (@base == MathS.e) return Evaluate(exponent).Exp(); diff --git a/Sources/AngouriMath/Numerics/PreciseEvaluation.cs b/Sources/AngouriMath/Numerics/PreciseEvaluation.cs index 262a4e4e4..2eb168b50 100644 --- a/Sources/AngouriMath/Numerics/PreciseEvaluation.cs +++ b/Sources/AngouriMath/Numerics/PreciseEvaluation.cs @@ -411,7 +411,32 @@ private PreciseComplexInterval Evaluate(Entity expr) return value; } + /// + /// The arithmetic is what nests deep, so it is kept apart from the other arms, whose + /// temporaries would otherwise widen every frame of the recursion, as in + /// . + /// private PreciseComplexInterval EvaluateNode(Entity expr) + { + switch (expr) + { + case Sumf(var left, var right): + return Evaluate(left) is { IsFinite: true } lSumf ? Add(lSumf, Evaluate(right)) : undefined; + case Minusf(var left, var right): + return Evaluate(left) is { IsFinite: true } lMinusf ? Subtract(lMinusf, Evaluate(right)) : undefined; + case Mulf(var left, var right): + return Multiply(Evaluate(left), Evaluate(right)); + case Divf(var left, var right): + return Evaluate(left) is { IsFinite: true } lDivf ? Divide(lDivf, Evaluate(right)) : undefined; + case Powf(var @base, Number.Integer power) when power.EInteger.CanFitInInt32(): + return Pow(Evaluate(@base), power.EInteger.ToInt32Checked()); + default: + return EvaluateOtherThanArithmetic(expr); + } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + private PreciseComplexInterval EvaluateOtherThanArithmetic(Entity expr) { switch (expr) { @@ -430,16 +455,6 @@ private PreciseComplexInterval EvaluateNode(Entity expr) return Real(Pi()); case Variable variable when variable == MathS.e: return Real(E()); - case Sumf(var left, var right): - return Evaluate(left) is { IsFinite: true } lSumf ? Add(lSumf, Evaluate(right)) : undefined; - case Minusf(var left, var right): - return Evaluate(left) is { IsFinite: true } lMinusf ? Subtract(lMinusf, Evaluate(right)) : undefined; - case Mulf(var left, var right): - return Multiply(Evaluate(left), Evaluate(right)); - case Divf(var left, var right): - return Evaluate(left) is { IsFinite: true } lDivf ? Divide(lDivf, Evaluate(right)) : undefined; - case Powf(var @base, Number.Integer power) when power.EInteger.CanFitInInt32(): - return Pow(Evaluate(@base), power.EInteger.ToInt32Checked()); case Powf(var @base, var exponent): return @base == MathS.e ? Exp(Evaluate(exponent)) : Pow(Evaluate(@base), Evaluate(exponent)); case Sinf(var argument):