diff --git a/docs/core/compatibility/11.md b/docs/core/compatibility/11.md index 521cb77a3ea0e..cf9ff3fa9f725 100644 --- a/docs/core/compatibility/11.md +++ b/docs/core/compatibility/11.md @@ -23,6 +23,7 @@ See [Breaking changes in ASP.NET Core 11](/aspnet/core/breaking-changes/11/overv | Title | Type of change | |-------------------------------------------------------------------|-------------------| | [CborReader and CborWriter enforce a default maximum nesting depth](core-libraries/11/cbor-max-depth.md) | Behavioral change | +| [Complex special-value results now follow C23 Annex G](core-libraries/11/complex-annex-g-special-values.md) | Behavioral change | | [CRC32 validation added when reading ZIP archive entries](core-libraries/11/ziparchive-entry-crc32-validation.md) | Behavioral change | | [DateOnly and TimeOnly TryParse methods throw for invalid input](core-libraries/11/dateonly-timeonly-tryparse-argumentexception.md) | Behavioral change | | [DeflateStream and GZipStream write headers and footers for empty payload](core-libraries/11/deflatestream-gzipstream-empty-payload.md) | Behavioral change | diff --git a/docs/core/compatibility/core-libraries/11/complex-annex-g-special-values.md b/docs/core/compatibility/core-libraries/11/complex-annex-g-special-values.md new file mode 100644 index 0000000000000..11036b543b782 --- /dev/null +++ b/docs/core/compatibility/core-libraries/11/complex-annex-g-special-values.md @@ -0,0 +1,79 @@ +--- +title: "Breaking change: System.Numerics.Complex special-value results now follow C23 Annex G" +description: "Learn about the breaking change in .NET 11 where System.Numerics.Complex arithmetic and math functions return C23 Annex G-conformant special values for signed zeros, infinities, and NaNs." +ms.date: 08/04/2026 +ai-usage: ai-assisted +--- + +# System.Numerics.Complex special-value results now follow C23 Annex G + + arithmetic operators and math functions now produce the special-value results (for signed zeros, infinities, and NaNs) required by C23 Annex G (IEC 60559-compatible complex arithmetic). Because `Complex` now delegates most of its implementation to the new `Complex` type, the conformant special-value handling flows through to it. + +## Version introduced + +.NET 11 Preview 7 + +## Previous behavior + +Previously, for non-finite (and some overflowing) inputs, `Complex` arithmetic and elementary functions frequently returned `(NaN, NaN)` even when a directed infinity or signed result was mathematically appropriate. + +```csharp +using System.Numerics; + +Complex.Atan(new Complex(double.PositiveInfinity, 1.0)); // (NaN, NaN) +Complex.Acos(new Complex(double.NegativeInfinity, double.NaN)); // (NaN, NaN) +Complex.Cosh(new Complex(double.PositiveInfinity, double.PositiveInfinity)); // (NaN, NaN) + +// An infinite operand could collapse the product to NaN: +new Complex(double.PositiveInfinity, double.PositiveInfinity) * new Complex(1.0, 0.0); // (NaN, NaN) +``` + +## New behavior + +Starting in .NET 11, the same inputs return the C23 Annex G special values. + +```csharp +using System.Numerics; + +Complex.Atan(new Complex(double.PositiveInfinity, 1.0)); // (π/2, 0) +Complex.Acos(new Complex(double.NegativeInfinity, double.NaN)); // (NaN, +∞) +Complex.Cosh(new Complex(double.PositiveInfinity, double.PositiveInfinity)); // (+∞, NaN) + +// An infinite operand now yields a directed infinity (Annex G.5.1 recovery): +new Complex(double.PositiveInfinity, double.PositiveInfinity) * new Complex(1.0, 0.0); // (+∞, +∞) +``` + +Division by a zero divisor is likewise governed by Annex G: the result is a directed infinity, or NaN for `0/0`. For example, `(1, 0) / (0, 0)` yields an infinite real component rather than a fully NaN result. + +The change spans `operator *`, `operator /`, `Multiply`, `Divide`, `Reciprocal`, `Abs`, `Pow`, and the elementary functions (`Sqrt`, `Exp`, `Log`, `Log10`, and the trigonometric, hyperbolic, and inverse-trigonometric functions). One case Annex G leaves explicitly unspecified, that is, the sign of a zero-valued quotient component from `operator /`, might also differ. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +Complex numbers are outside the scope of IEEE 754 itself, so C23 Annex G is the relevant specification of the special-value behavior IEEE 754 otherwise implies for the scalar operations complex arithmetic is built on. The previous implementation returned `NaN` for many inputs where Annex G requires a directed infinity or a signed result, which is both non-conformant and less useful for downstream numerical code, because it lost the sign or direction information that an infinite intermediate value carries. The new generic `Complex` type was made conformant, and the shipped `Complex` type inherits that conformance by delegation. + +For more information, see [dotnet/runtime#131132](https://github.com/dotnet/runtime/pull/131132). + +## Recommended action + +Most code benefits from the more accurate results and needs no change. If your code explicitly depends on the previous `(NaN, NaN)` results for special-value inputs, update it to expect the Annex G values. Such code might be tests that assert `NaN` for `Complex` operations on infinities, or logic that treats any non-finite input as producing `NaN`. + +There's no compatibility switch to restore the previous behavior. + +## Affected APIs + +- +- +- +- +- +- +- and +- +- +- (all overloads) and +- , , , , , +- , , diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index aee280b97e29f..8e3a6892c202e 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -12,6 +12,8 @@ items: items: - name: CborReader and CborWriter enforce a default maximum nesting depth href: core-libraries/11/cbor-max-depth.md + - name: Complex special-value results now follow C23 Annex G + href: core-libraries/11/complex-annex-g-special-values.md - name: CRC32 validation added when reading ZIP archive entries href: core-libraries/11/ziparchive-entry-crc32-validation.md - name: DateOnly and TimeOnly TryParse methods throw for invalid input