From 043b02df1a1bddbcba385e6a1e7f390748b96704 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Fri, 30 Oct 2026 15:38:25 +0000 Subject: [PATCH] The imaginary part of a value that does not exist has none Im(1/0) was 0, and so was Im(arccos(pi) provided pi < 3), where Re, conj, arg, abs and floor of the same values are NaN. Imf.ImaginaryPart answered any Complex with its imaginary part, and NaN is a Real, whose imaginary part is 0. A NaN argument is now NaN, before that arm. ImaginaryPartOfNaNTest takes Im of three values that do not exist, evaluated, simplified and substituted, and four of them fail on master. Re(1/0) and the imaginary parts of 2 + 3i, 5 and -oo pin what has not changed. Im is new since 2.6.0 (#2145), where im(1/0) was the product im * (1/0), so no answer changes against it. Found by work/domaincheck. Fixes #2253. Co-Authored-By: Claude Opus 5.5 (1M context) --- Sources/.editorconfig | 3 ++ ...aluation.Continuous.Arithmetics.Classes.cs | 3 ++ .../Convenience/ImaginaryPartOfNaNTest.cs | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 Sources/Tests/UnitTests/Convenience/ImaginaryPartOfNaNTest.cs diff --git a/Sources/.editorconfig b/Sources/.editorconfig index b677d246c..a8e9e46ef 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -932,6 +932,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Convenience/ArcsineOfARealPastOneTest.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/Convenience/ImaginaryPartOfNaNTest.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 + [AngouriMath/Functions/Compilation/RealProducts.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/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs index f8a8bc6fd..4cac48015 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 @@ -826,6 +826,9 @@ public partial record Imf // im(prime(x)) has no value at x = -3. private static Entity? ImaginaryPart(Entity argument, bool isExact) => argument switch { + // A number that does not exist has no parts. NaN is a Real, whose imaginary part is 0, so + // im(1/0) was 0. https://github.com/asc-community/AngouriMath/issues/2253 + Complex { IsNaN: true } => Real.NaN, Complex number => number.ImaginaryPart, Conjugatef(var z) => (-new Imf(z)).InnerSimplified(isExact), Sumf(var left, var right) => (new Imf(left) + new Imf(right)).InnerSimplified(isExact), diff --git a/Sources/Tests/UnitTests/Convenience/ImaginaryPartOfNaNTest.cs b/Sources/Tests/UnitTests/Convenience/ImaginaryPartOfNaNTest.cs new file mode 100644 index 000000000..b292454f4 --- /dev/null +++ b/Sources/Tests/UnitTests/Convenience/ImaginaryPartOfNaNTest.cs @@ -0,0 +1,44 @@ +// +// 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; +using AngouriMath.Extensions; +using Xunit; + +namespace AngouriMath.Tests.Convenience +{ + /// + /// The imaginary part of a value that does not exist has none, as its real part has none, where it was 0: NaN + /// is a , whose imaginary part is 0. + /// #2253 + /// + [Trait("Area", "Convenience")] + public sealed class ImaginaryPartOfNaNTest + { + [Theory] + [InlineData("Im(1/0)")] + [InlineData("Im(arccos(pi) provided pi < 3)")] + [InlineData("Im(1/0) + 1")] + [InlineData("Re(1/0)")] + public void ItHasNoValue(string expression) + { + Assert.True(expression.ToEntity().Evaled.IsNaN, $"{expression} evaluates to {expression.ToEntity().Evaled}"); + Assert.True(expression.ToEntity().Simplify().IsNaN, $"{expression} simplifies to {expression.ToEntity().Simplify()}"); + } + + [Fact] + public void SubstitutedItHasNoValue() + => Assert.True("Im(x)".ToEntity().Substitute("x", "1/0".ToEntity()).Evaled.IsNaN); + + [Theory] + [InlineData("Im(2 + 3i)", "3")] + [InlineData("Im(5)", "0")] + [InlineData("Im(-oo)", "0")] + public void ANumberHasItsImaginaryPart(string expression, string part) + => Assert.Equal(part.ToEntity().Evaled, expression.ToEntity().Evaled); + } +}