From 6243980a00367f24fba9774bf99d12568c42efed Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sat, 31 Oct 2026 05:35:15 +0000 Subject: [PATCH] An infinity over a vanishing divisor is the infinity of the signs limit(ln(x^2) / (cos(x) - 1), x, 0) was NaN, the claim that there is no limit, where it is +oo from both sides. Each side's descent put the parts' limits in place of the parts and read (-oo) / 0, which says nothing about the side the divisor vanishes from and is NaN, and DivergesAtAVanishingDivisor, which reads that side, asked for a finite dividend. An infinity with a sign over a divisor vanishing from one side is no more indeterminate than a number is: it is the infinity of the two signs' product. The rule now takes one. AnInfinityOverAVanishingDivisorTest takes four two-sided limits that were NaN, four one-sided and two-sided ones that were answered and are unchanged, and three that have no limit and stay NaN, x^x at 0 among them; the four fail on master. The suite, the trio, F#, AOT and the eight harnesses pass. #2275's entry for ln(x^2) / ln(cos(x)) now reads +oo. The issue put the cause at WhereBothSidesAgree's real-codomain gate. Opening the gate changed nothing: each side was still (-oo) / 0. Fixes #2274. Co-Authored-By: Claude Opus 5.5 (1M context) --- BREAKING-CHANGES.md | 16 ++++++- Sources/.editorconfig | 3 ++ .../Continuous/Limits/Transformations.cs | 8 ++-- .../AnInfinityOverAVanishingDivisorTest.cs | 43 +++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 Sources/Tests/UnitTests/Calculus/AnInfinityOverAVanishingDivisorTest.cs diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 9639ad741..2212639e4 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -85,7 +85,7 @@ and some are left unevaluated ([#2267](https://github.com/asc-community/AngouriM |---|---|---| | `"limitright(ln(x) / ln(cos(x)), x, 0)".ToEntity().Simplify()` | `-oo` | `+oo` | | `"limitright(ln(sin(x)) / ln(cos(x)), x, 0)".ToEntity().Simplify()` | `-oo` | `+oo` | -| `"limit(ln(x^2) / ln(cos(x)), x, 0)".ToEntity().Simplify()` | `-oo` | `NaN`, which is wrong too: both sides are `+oo` ([#2274](https://github.com/asc-community/AngouriMath/issues/2274)) | +| `"limit(ln(x^2) / ln(cos(x)), x, 0)".ToEntity().Simplify()` | `-oo` | `+oo`, by [#2274](https://github.com/asc-community/AngouriMath/issues/2274) | ### A value put in for a derivative's variable is where it is evaluated @@ -544,6 +544,20 @@ the expression's own domain as its condition ([#2142](https://github.com/asc-com | `"(1 - cos(a))/(1 + cos(a))/tan(a/2)^2".Simplify()` | `(1 - cos(a)) / ((cos(a) + 1) * tan(a / 2) ^ 2)` | `1 provided not cos(a) + 1 = 0 and not tan(a / 2) = 0 and not cos(a / 2) = 0` | | `"(cos(2*x) - 1)^2 + sin(2*x)^2 - 4*sin(x)^2".Simplify()` ([#2133](https://github.com/asc-community/AngouriMath/issues/2133)) | `2 + (-2) * cos(2 * x) + (-4) * sin(x) ^ 2` | `0` | +### An infinity over a vanishing divisor is the infinity of the signs + +**Silent: a limit of a quotient whose dividend tends to an infinity and whose divisor vanishes from one side is that +infinity times the divisor's sign, where a two-sided one was `NaN`.** The quotient of the parts' limits, `(-oo) / 0`, says +nothing about the side the divisor vanishes from, and the rule that reads the side asked for a finite dividend. So each +side of `ln(x^2) / (cos(x) - 1)` at 0 came back undecided, and the two-sided limit, `+oo` from both, was `NaN` +([#2274](https://github.com/asc-community/AngouriMath/issues/2274)). + +| Input | Was (2.6.0) | Now | +|---|---|---| +| `"limit(ln(x^2) / (cos(x) - 1), x, 0)".ToEntity().Simplify()` | `NaN` | `+oo` | +| `"limit(ln(x^2) / ln(1 - x^2/2), x, 0)".ToEntity().Simplify()` | `NaN` | `+oo` | +| `"limit(ln(abs(x)) / ln(cos(x)), x, 0)".ToEntity().Simplify()` | `NaN` | `+oo` | + ### The double factorial is the postfix `n!!` **Not silent: `n!!` is now the double factorial, where it was a parse error.** It is the product of the positive integers diff --git a/Sources/.editorconfig b/Sources/.editorconfig index b78feabcd..f19e17474 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -185,6 +185,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Calculus/BoundNameTest.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/AnInfinityOverAVanishingDivisorTest.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/Core/BinderShadowingTest.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/Transformations.cs b/Sources/AngouriMath/Functions/Continuous/Limits/Transformations.cs index c87699f8d..2447b012e 100644 --- a/Sources/AngouriMath/Functions/Continuous/Limits/Transformations.cs +++ b/Sources/AngouriMath/Functions/Continuous/Limits/Transformations.cs @@ -1056,9 +1056,11 @@ internal static bool IsDeterminate(Entity combined, Variable x) if (EvalAssumingContinuous(divisor.Limit(x, dest, side)) is not Real { IsZero: true }) return null; // A dividend that vanishes too makes the quotient indeterminate rather than - // divergent, and one that diverges is a different question again. Only a dividend - // with a definite non-zero size leaves the divisor to decide the answer. - if (EvalAssumingContinuous(dividend.Limit(x, dest, side)) is not Real { IsFinite: true, IsZero: false } dividendLimit) + // divergent. One with a definite sign that does not vanish, a finite one or an + // infinity, leaves the divisor to decide the answer: -oo over a divisor vanishing from + // below is +oo, and ln(x^2) / (cos(x) - 1) at 0 was left as (-oo) / 0, which is NaN. + // https://github.com/asc-community/AngouriMath/issues/2274 + if (EvalAssumingContinuous(dividend.Limit(x, dest, side)) is not Real { IsZero: false, IsNaN: false } dividendLimit) return null; if (SignFromVanishingOrder(divisor, x, dest, side) is not { } divisorSign) return null; diff --git a/Sources/Tests/UnitTests/Calculus/AnInfinityOverAVanishingDivisorTest.cs b/Sources/Tests/UnitTests/Calculus/AnInfinityOverAVanishingDivisorTest.cs new file mode 100644 index 000000000..83ea1a8ef --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/AnInfinityOverAVanishingDivisorTest.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 quotient whose dividend tends to an infinity and whose divisor vanishes from one side tends to the infinity of + /// the two signs' product. The quotient of the parts' limits, (-oo) / 0, says nothing about the divisor's side and is + /// NaN, and the rule that reads the side asked for a finite dividend: ln(x^2) / (cos(x) - 1) at 0, +oo from both + /// sides, was NaN, the claim that it has no limit. + /// #2274 + /// + [Trait("Area", "Calculus")] + public sealed class AnInfinityOverAVanishingDivisorTest + { + [Theory] + [InlineData("limit(ln(x^2) / ln(1 - x^2/2), x, 0)", "+oo")] + [InlineData("limit(ln(x^2) / (cos(x) - 1), x, 0)", "+oo")] + [InlineData("limit(ln(abs(x)) / ln(cos(x)), x, 0)", "+oo")] + [InlineData("limit(ln(x^2) / ln(cos(x)), x, 0)", "+oo")] + [InlineData("limitright(ln(x) / sin(x), x, 0)", "-oo")] + [InlineData("limitleft(ln(-x) / sin(x), x, 0)", "+oo")] + [InlineData("limitright((1/x) / sin(x), x, 0)", "+oo")] + [InlineData("limit(1/x^2, x, 0)", "+oo")] + public void ItIsTheInfinityOfTheSigns(string limit, string value) + => Assert.Equal(value.ToEntity(), limit.ToEntity().Simplify()); + + /// Where the sides disagree, or one has no real value, there is still no limit. + [Theory] + [InlineData("limit(1/x, x, 0)")] + [InlineData("limit(x^x, x, 0)")] + [InlineData("limit(ln(x) / x, x, 0)")] + public void WhereTheSidesDoNotAgreeThereIsNone(string limit) + => Assert.Equal(MathS.NaN, limit.ToEntity().Simplify()); + } +}