diff --git a/Sources/AngouriMath/Numerics/ComplexParts.cs b/Sources/AngouriMath/Numerics/ComplexParts.cs index 147884535..72a5f9b1a 100644 --- a/Sources/AngouriMath/Numerics/ComplexParts.cs +++ b/Sources/AngouriMath/Numerics/ComplexParts.cs @@ -30,9 +30,15 @@ internal static class ComplexParts private static double Arg(double re, double im) => re == 0 && im == 0 ? double.NaN : Math.Atan2(im == 0 ? 0.0 : im, re == 0 ? 0.0 : re); - public static NumericsComplex Re(NumericsComplex z) => z.Real; + /// + /// The real and the imaginary part, which a number with no value does not have either: a + /// NaN in one part is the whole number's, as a NaN over the doubles has an imaginary part + /// of NaN. Taking only the other part gave Im(Im(x / x)) the value 0 at 0, where + /// x / x has none. + /// + public static NumericsComplex Re(NumericsComplex z) => double.IsNaN(z.Imaginary) ? double.NaN : z.Real; public static double Re(double x) => x; - public static NumericsComplex Im(NumericsComplex z) => z.Imaginary; + public static NumericsComplex Im(NumericsComplex z) => double.IsNaN(z.Real) ? double.NaN : z.Imaginary; public static double Im(double x) => double.IsNaN(x) ? double.NaN : 0; } } diff --git a/Sources/Tests/UnitTests/Convenience/ComplexPartsCompilationTest.cs b/Sources/Tests/UnitTests/Convenience/ComplexPartsCompilationTest.cs index 96ee8e09c..099825f7f 100644 --- a/Sources/Tests/UnitTests/Convenience/ComplexPartsCompilationTest.cs +++ b/Sources/Tests/UnitTests/Convenience/ComplexPartsCompilationTest.cs @@ -59,6 +59,34 @@ public void TheArgumentOfZeroHasNoValue() Assert.Equal(MathS.NaN, "arg(0)".ToEntity().Evaled); } + /// + /// The parts of a value that is not there are not there either. x / x at 0 compiles + /// to NaN + NaN i, its imaginary part to NaN, and the imaginary part of that + /// was 0, a value where the interpreter has none. + /// + [Theory] + [InlineData("Im(Im(x / x))")] + [InlineData("Im(Re(x / x))")] + [InlineData("Re(Im(x / x))")] + [InlineData("Im(Im(sqrt(x) / sqrt(x)))")] + public void APartOfNoValueHasNoValue(string expression) + { + Assert.True(expression.ToEntity().Substitute("x", 0).Evaled.IsNaN); + Assert.True(double.IsNaN(expression.ToEntity().Compile("x").Call(0).Real), $"FastExpression gives {expression.ToEntity().Compile("x").Call(0)}"); + Assert.True(double.IsNaN(expression.ToEntity().Compile("x")(0).Real), + $"LINQ gives {expression.ToEntity().Compile("x")(0)}"); + } + + /// A NaN in either part of an argument is the whole argument's. + [Theory] + [InlineData("Re(x)", 1, double.NaN)] + [InlineData("Im(x)", double.NaN, 1)] + public void ANaNInOnePartIsTheWholeNumbers(string expression, double re, double im) + { + Assert.True(double.IsNaN(expression.ToEntity().Compile("x").Call(new NumericsComplex(re, im)).Real)); + Assert.True(double.IsNaN(expression.ToEntity().Compile("x")(new NumericsComplex(re, im)).Real)); + } + /// Over doubles, the argument of a negative number is pi, and the imaginary part is 0. [Theory] [InlineData("arg(x)", -2, System.Math.PI)]