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