diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 0e168e8cc..8f83af08f 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -88,6 +88,19 @@ definite integral, a sum, a product and a limit bind their variable, and are unc | `"derivative(a x^2, x)".ToEntity().Substitute("a", "x").Evaled` | `2 * x_1 * x` | `2 * x * x` | | `"derivative(x^3, x)".ToEntity().Substitute("x", 1)` | `derivative(x ^ 3, x)` | `apply(lambda(x, derivative(x ^ 3, x)), 1)` | +### A quotient of logarithms tends to the logarithms of its arguments' limits + +**Silent: a limit of a quotient of logarithms whose arguments tend to symbolic values answered the quotient of those +values.** The logarithm is continuous, so the quotient tends to the quotient of the values' logarithms. With numbers it +did, and `ln(x + 2) / ln(x + 3)` at 0 was `ln(2) / ln(3)`. With symbols it was not: +`ln(y + x) / ln(z + x)` at 0 was `y / z` ([#2271](https://github.com/asc-community/AngouriMath/issues/2271)). + +| Input | Was (2.6.0) | Now | +|---|---|---| +| `"limit(ln(y + x) / ln(z + x), x, 0)".ToEntity().Simplify()` | `y / z` | `ln(y) / ln(z)` | +| `"limit(ln(a + 1/x) / ln(b + 1/x), x, +oo)".ToEntity().Simplify()` | `a / b` | `ln(a) / ln(b)` | +| `"limit(ln(1 + x) / ln(y + x), x, 0)".ToEntity().Simplify()` | `1 / y` | `0 provided not ln(y) = 0` | + ### A quadratic whose discriminant is a square is answered without the root **Silent: the same roots, written as what they are.** The quadratic formula wrote `sqrt(b^2 - 4ac)` whatever the diff --git a/Sources/.editorconfig b/Sources/.editorconfig index a06523e7d..183a74662 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -75,6 +75,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Calculus/ModulusPhaseTest.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/LogarithmsOfSymbolicLimitsTest.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/LimitAtAJumpTest.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/Limit.Solvers.cs b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs index 088f31ca9..cd03e3cdc 100644 --- a/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs +++ b/Sources/AngouriMath/Functions/Continuous/Limits/Solvers/Limit.Solvers.cs @@ -314,7 +314,10 @@ private static bool IsRealValued(Entity expr, Variable x) { Evaled.IsNaN: true } => null, { } res when res.ContainsNode("+oo") || res.ContainsNode("-oo") => div.InnerSimplified, { Evaled: Complex } limit => limit, - _ => upperLogLimit / lowerLogLimit, + // The logarithm is continuous, so the quotient tends to the quotient of the + // limits' logarithms, not of the limits: ln(y + x) / ln(z + x) at 0 answered + // y / z -- https://github.com/asc-community/AngouriMath/issues/2271. + _ => div.InnerSimplified, }; } } diff --git a/Sources/Tests/UnitTests/Calculus/LogarithmsOfSymbolicLimitsTest.cs b/Sources/Tests/UnitTests/Calculus/LogarithmsOfSymbolicLimitsTest.cs new file mode 100644 index 000000000..40629ce6d --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/LogarithmsOfSymbolicLimitsTest.cs @@ -0,0 +1,33 @@ +// +// 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 quotient of logarithms whose arguments tend to symbolic values tends to the quotient of those values' logarithms, + /// the logarithm being continuous. It answered the quotient of the values themselves: ln(y + x) / ln(z + x) at 0 was + /// y / z, while the same limit with numbers, ln(x + 2) / ln(x + 3), was ln(2) / ln(3). + /// #2271 + /// + [Trait("Area", "Calculus")] + public sealed class LogarithmsOfSymbolicLimitsTest + { + [Theory] + [InlineData("limit(ln(y + x) / ln(z + x), x, 0)", "ln(y) / ln(z)")] + [InlineData("limitright(ln(a + x) / ln(b + x), x, 0)", "ln(a) / ln(b)")] + [InlineData("limit(ln(a + 1/x) / ln(b + 1/x), x, +oo)", "ln(a) / ln(b)")] + [InlineData("limit(ln(a + e^(-x)) / ln(b + e^(-x)), x, +oo)", "ln(a) / ln(b)")] + [InlineData("limit(log(b + 1/x, a + 1/x), x, +oo)", "ln(a) / ln(b)")] + [InlineData("limit(ln(1 + x) / ln(y + x), x, 0)", "0 provided not ln(y) = 0")] + [InlineData("limit(ln(x + 2) / ln(x + 3), x, 0)", "ln(2) / ln(3)")] + public void ItIsTheQuotientOfTheLogarithms(string limit, string value) + => Assert.Equal(value.ToEntity(), limit.ToEntity().Simplify()); + } +}