From bb691c99fcc7f0ebd735563db0f83b988aba153c Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 13 Oct 2026 02:54:03 +0000 Subject: [PATCH 1/2] Zero to a non-real power is defined where its real part is positive Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- ...aluation.Continuous.Arithmetics.Classes.cs | 15 ++++++-- .../UnitTests/Calculus/DerivativeGapsTest.cs | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs index 75855173a..28abae30b 100644 --- a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs @@ -255,8 +255,19 @@ public partial record Powf // https://github.com/asc-community/AngouriMath/issues/721 private protected override Entity IntrinsicCondition => Codomain < Domain.Complex && IsEvenRoot - ? Base >= 0 & (!Base.EqualTo(0) | Exponent > 0) - : (!Base.EqualTo(0) | Exponent > 0); + ? Base >= 0 & WhereZeroIsDefined + : WhereZeroIsDefined; + + /// + /// 0^w is defined where Re(w) > 0. For a non-real number w, + /// w > 0 has no value, the complex numbers not being ordered, and made the + /// whole condition NaN, so 0 b^i was NaN; its real part is read instead. + /// #1865 + /// + private Entity WhereZeroIsDefined + => (Exponent is Complex ? Exponent : Exponent.Vars.Any() ? null : Exponent.Evaled) is Complex exponent and not Real + ? exponent.RealPart.IsPositive ? Boolean.True : !Base.EqualTo(0) + : !Base.EqualTo(0) | Exponent > 0; /// /// Whether the exponent is a literal rational whose denominator is even — the case diff --git a/Sources/Tests/UnitTests/Calculus/DerivativeGapsTest.cs b/Sources/Tests/UnitTests/Calculus/DerivativeGapsTest.cs index 8bcb0ad02..9a8b1b756 100644 --- a/Sources/Tests/UnitTests/Calculus/DerivativeGapsTest.cs +++ b/Sources/Tests/UnitTests/Calculus/DerivativeGapsTest.cs @@ -107,5 +107,40 @@ public void AntiderivativeOfAPowerDifferentiatesBackEverywhere() // only in how the condition nests. public void SymbolicExponentsAreUnaffected(string input, string expected) => Assert.Equal(expected, input.ToEntity().Differentiate("x").Simplify().Stringize()); + + // `0^w` is defined where `Re(w) > 0`. A power's condition was `not b = 0 or w > 0`, + // NaN for a non-real `w`, so zero times `b^i` was NaN and so was the derivative of + // anything with a constant `b^i` in it. + // https://github.com/asc-community/AngouriMath/issues/1865 + [Theory] + [InlineData("0 * b ^ i", "0 provided not b = 0")] + [InlineData("b ^ i - b ^ i", "0 provided not b = 0")] + [InlineData("0 * b ^ (i / 2)", "0 provided not b = 0")] + [InlineData("0 * b ^ (-1 + i)", "0 provided not b = 0")] + [InlineData("0 * b ^ (2 + i)", "0")] + [InlineData("0 ^ i", "NaN")] + public void ZeroTimesAPowerWithANonRealExponent(string input, string expected) => + Assert.Equal(expected, input.ToEntity().Simplify().Stringize()); + + [Theory] + [InlineData("x * b ^ i")] + [InlineData("sec(a + i * ln(x)) ^ 3")] + [InlineData("x * sin(a + ln(c * x) * sqrt(-4))")] + public void AConstantWithANonRealExponentDifferentiates(string integrand) + { + var f = integrand.ToEntity(); + var antiderivative = integrand.StartsWith("x * b") ? "x ^ 2 / 2 * b ^ i".ToEntity() : f.Integrate("x").Substitute("C", 0); + // Differentiated while still symbolic, then pinned: pinning first never saw the NaN. + var derivative = antiderivative.Differentiate("x"); + Entity Pinned(Entity e) => e.Substitute("a", "1/4".ToEntity()).Substitute("b", 2).Substitute("c", 2); + foreach (var point in new[] { "0.57", "1.29" }) + { + var want = Pinned(f).Substitute("x", point.ToEntity()).EvalNumerical(); + var got = Pinned(derivative).Substitute("x", point.ToEntity()).EvalNumerical(); + var difference = (got - want).EvalNumerical(); + Assert.True(System.Math.Abs((double)difference.RealPart) + System.Math.Abs((double)difference.ImaginaryPart) < 1e-9, + $"d/dx of the antiderivative of {integrand} is {got} at x = {point}, where it is {want}"); + } + } } } From a32a532a4be77f5dde213ddf04a08cae8cbb9467 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Tue, 13 Oct 2026 04:12:56 +0000 Subject: [PATCH 2/2] Zero times a power with a non-real exponent in BREAKING-CHANGES Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- BREAKING-CHANGES.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index fcd59239a..38f06d56b 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -151,6 +151,21 @@ an arm for each sign of a quantity that is not real, `x^2 provided not x = 0` be | `"piecewise(2 * x provided not x = 0, 3 * x ^ 2 provided i - 1 < 0)".ToEntity().InnerSimplified` | `NaN` | `2 * x` where `x` is not 0 | | `"piecewise(1 provided i < 0, 2 provided i > 0)".ToEntity().InnerSimplified` | `NaN` | `NaN`, as before: no case holds | +### Zero times a power with a non-real exponent is zero where the power is defined + +**A value where there was NaN.** `0 b^i` simplified to NaN, and so did `b^i - b^i`. That in turn made `x b^i`'s +derivative NaN, along with the derivative of every antiderivative with a constant like `(e^a)^i` in it. A power's +condition was `not b = 0 or w > 0`, and `w > 0` has no value for a non-real `w`, since the complex numbers are not +ordered. `0^w` is defined where `Re(w) > 0`, and that is the condition now +([#1865](https://github.com/asc-community/AngouriMath/issues/1865)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"0 * b^i".ToEntity().Simplify()` | `NaN` | `0 provided not b = 0` | +| `"b^i - b^i".ToEntity().Simplify()` | `NaN` | `0 provided not b = 0` | +| `"0 * b^(2 + i)".ToEntity().Simplify()` | `NaN` | `0` | +| `"x * b^i".ToEntity().Differentiate("x")` | `NaN` | `b ^ i provided not b = 0` | + ### The factorial far from zero, and a quotient by a number whose modulus is nearly whole The numerical factorial is Spouge's approximation, and it holds right of zero. Used left of zero it