diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 6e558804a..9c90aea54 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -121,6 +121,19 @@ carried it once combined: a second derivative of `1/sqrt(x^2 + 13)` stated `not
| `"(a provided b > 0) + (c provided b > 0)".ToEntity().InnerSimplified` | `a + c provided b > 0 and b > 0` | `a + c provided b > 0` |
| `MathS.Equations("sqrt(y) - x", "y - a").Solve("x", "y")` | `[[sqrt(a), (sqrt(a)) ^ 2], [-sqrt(a), (-sqrt(a)) ^ 2]]` | `[[sqrt(a) provided C(sqrt(a)), (sqrt(a)) ^ 2 provided C(sqrt(a))], [-sqrt(a) provided C(-sqrt(a)), (-sqrt(a)) ^ 2 provided C(-sqrt(a))]]`, `C(v)` being `v = 0 or -1/2 * pi < arg(v) and arg(v) <= 1/2 * pi` |
+### A limit of a logarithm that is not decided is left unevaluated
+
+**Not silent: what overflowed the stack now returns.** A limit of a logarithm whose argument has no limit, as
+`ln(2 + sin(x))` at `+oo`, overflowed the stack and took the process down. A limit node simplifies its expression evaluated,
+where `ln(f)` is `log(2.718..., f)`, and that base was not read as `e`: the quotient `ln(f) / ln(2.718...)` it was rewritten
+as asked the limit of `ln(f)` again, through a limit node of its own
+([#2273](https://github.com/asc-community/AngouriMath/issues/2273)).
+
+| Input | Was (2.6.0) | Now |
+|---|---|---|
+| `"limit(ln(2 + sin(x)), x, +oo)".ToEntity().Simplify()` | stack overflow | `limit(ln(2 + sin(x)), x, +oo)` |
+| `"limitright(ln(sin(1/x) + 2), x, 0)".ToEntity().Simplify()` | stack overflow | `limitright(ln(2 + sin(1 / x)), x, 0)` |
+
### Primality is decided by Miller–Rabin and Lucas–Lehmer, and finishes
**Silent: a membership in `PP` left open past the machine word is decided where a test proves it, and one that did
diff --git a/Sources/.editorconfig b/Sources/.editorconfig
index e6a04a3ac..307f85609 100644
--- a/Sources/.editorconfig
+++ b/Sources/.editorconfig
@@ -114,6 +114,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[Tests/UnitTests/Calculus/LimitsTheIssueListedTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n
+[Tests/UnitTests/Calculus/UndecidedLogarithmLimitTest.cs]
+file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n
+
[Tests/UnitTests/Calculus/PowerSubstitutionIntegralTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n
diff --git a/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Solvers.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Solvers.Definition.cs
index 9fba3b24c..2340a1746 100644
--- a/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Solvers.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Solvers.Definition.cs
@@ -156,9 +156,21 @@ internal static partial class LimitFunctional
[System.ThreadStatic] private static int bothSidesDepth;
+ ///
+ /// A logarithm to a base other than e as a quotient of natural logarithms.
+ ///
+ ///
+ /// A base that is e evaluated is e. The limit of a limit node's evaluation is taken of its
+ /// expression evaluated, in which ln(f) is log(2.718..., f), and as a quotient that is
+ /// ln(f) / ln(2.718...), whose first remarkable limit asks the limit of ln(f) through a
+ /// limit node of its own -- which is evaluated, and so asks the same question again. Where
+ /// the limit of ln(f) is not decided, that did not end, and the stack overflowed.
+ /// #2273
+ ///
private static Entity ExpandLogarithm(Entity expr)
=> expr switch
{
+ Logf(var @base, var antilog) when @base == MathS.e.Evaled => MathS.Ln(antilog),
Logf(var @base, var antilog) when @base != MathS.e => MathS.Ln(antilog) / MathS.Ln(@base),
_ => expr
};
diff --git a/Sources/Tests/UnitTests/Calculus/UndecidedLogarithmLimitTest.cs b/Sources/Tests/UnitTests/Calculus/UndecidedLogarithmLimitTest.cs
new file mode 100644
index 000000000..eac6d99cf
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/UndecidedLogarithmLimitTest.cs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2019-2026 Angouri.
+// AngouriMath is licensed under MIT.
+// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
+// Website: https://am.angouri.org.
+//
+
+using AngouriMath.Extensions;
+using Xunit;
+
+namespace AngouriMath.Tests.Calculus
+{
+ ///
+ /// A limit of a logarithm that is not decided is left unevaluated, where it overflowed the stack. A limit node simplifies
+ /// its expression evaluated, in which ln(f) is log(2.718..., f), the base was not read as e, and the quotient
+ /// ln(f) / ln(2.718...) it was rewritten as asked the limit of ln(f) again through a limit node of its own. None of these
+ /// has a limit, as the argument oscillates, so NaN would be right as well.
+ /// #2273
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class UndecidedLogarithmLimitTest
+ {
+ [Theory]
+ [InlineData("limitright(ln(sin(1/x) + 2), x, 0)")]
+ [InlineData("limit(ln(sin(1/x) + 2), x, 0)")]
+ [InlineData("limitleft(ln(2 + cos(1/x)), x, 0)")]
+ [InlineData("limit(ln(2 + sin(x)), x, +oo)")]
+ [InlineData("limit(sqrt(x) * ln(2 + sin(1/x)), x, 0)")]
+ public void ItIsLeftUnevaluated(string limit)
+ {
+ var answer = limit.ToEntity().Simplify();
+ Assert.True(answer is Entity.Limitf || answer == MathS.NaN, $"{limit} is {answer}");
+ }
+
+ /// A logarithm whose limit is decided is answered as before.
+ [Theory]
+ [InlineData("limit(ln(x) / ln(2), x, 4)", "2")]
+ [InlineData("limit(ln(1 + x) / x, x, 0)", "1")]
+ [InlineData("limitright(ln(x) * x, x, 0)", "0")]
+ public void ADecidedOneIsAnswered(string limit, string value)
+ => Assert.Equal(value.ToEntity(), limit.ToEntity().Simplify());
+ }
+}