From 5d8425644a8d8f8ea0079f2800540dee993c6e11 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 7 Jun 2023 12:12:41 -0400 Subject: [PATCH 01/19] Initial work on docc setup. --- .../Documentation.docc/Complex.md | 51 +++++++ .../Documentation.docc/ComplexModule.md | 63 ++++++++ .../Documentation.docc/Infinity.md | 48 ++++++ .../Documentation.docc/Magnitude.md | 137 ++++++++++++++++++ .../Documentation.docc/Augmented.md | 20 +++ .../Documentation.docc/RealModule.md | 13 ++ .../RealModule/Documentation.docc/Relaxed.md | 46 ++++++ 7 files changed, 378 insertions(+) create mode 100644 Sources/ComplexModule/Documentation.docc/Complex.md create mode 100644 Sources/ComplexModule/Documentation.docc/ComplexModule.md create mode 100644 Sources/ComplexModule/Documentation.docc/Infinity.md create mode 100644 Sources/ComplexModule/Documentation.docc/Magnitude.md create mode 100644 Sources/RealModule/Documentation.docc/Augmented.md create mode 100644 Sources/RealModule/Documentation.docc/RealModule.md create mode 100644 Sources/RealModule/Documentation.docc/Relaxed.md diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md new file mode 100644 index 00000000..63c389b4 --- /dev/null +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -0,0 +1,51 @@ +# ``Complex`` + +## Topics + +### Real and imaginary parts + +A `Complex` value is represented with two `RealType` values, corresponding to +the real and imaginary parts of the number: +```swift +let z = Complex(1,-1) // 1 - i +let re = z.real // 1 +let im = z.imaginary // -1 +``` +All `Complex` numbers with a non-finite component is treated as a single +"point at infinity," with infinite magnitude and indeterminant phase. Thus, +the real and imaginary parts of an infinity are nan. +```swift +let w = Complex.infinity +w == -w // true +let re = w.real // .nan +let im = w.imag // .nan +``` +See for more details. + +- ``init(_:_:)`` +- ``init(_:)-5aesj`` +- ``init(imaginary:)`` +- ``real`` +- ``imaginary`` + +### Magnitude and norms + +See the article for more details. + +- ``magnitude`` +- ``length`` +- ``lengthSquared`` +- ``normalized`` + +### Polar representations + +- ``init(length:phase:)`` +- ``phase`` +- ``length`` +- ``polar`` + +### Conversions from other types + +- ``init(_:)-4csd3`` +- ``init(_:)-80jml`` +- ``init(exactly:)-767k9`` diff --git a/Sources/ComplexModule/Documentation.docc/ComplexModule.md b/Sources/ComplexModule/Documentation.docc/ComplexModule.md new file mode 100644 index 00000000..e1cd6c8a --- /dev/null +++ b/Sources/ComplexModule/Documentation.docc/ComplexModule.md @@ -0,0 +1,63 @@ +# ``ComplexModule`` + +Types and operations for working with complex numbers. + +## Representation + +The `Complex` type is generic over an associated `RealType`; complex numbers +are represented as two `RealType` values, the real and imaginary parts of the +number. +``` +let z = Complex(1, 2) +let re = z.real +let im = z.imaginary +``` + +### Memory layout + +A `Complex` value is stored as two `RealType` values arranged consecutively +in memory. Thus it has the same memory layout as: +- A Fortran complex value built on the corresponding real type (as used +by BLAS and LAPACK). +- A C struct with real and imaginary parts and nothing else (as used by +computational libraries predating C99). +- A C99 `_Complex` value built on the corresponding real type. +- A C++ `std::complex` value built on the corresponding real type. +Functions taking complex arguments in these other languages are not +automatically converted on import, but you can safely write shims that +map them into Swift types by converting pointers. + +## Real-Complex arithmetic + +Because the real numbers are a subset of the complex numbers, many +languages support arithmetic with mixed real and complex operands. +For example, C allows the following: +```c +#include +double r = 1; +double complex z = CMPLX(0, 2); // 2i +double complex w = r + z; // 1 + 2i +``` +The `Complex` type does not provide such mixed operators. There are two +reasons for this choice. First, Swift generally avoids mixed-type +arithmetic, period. Second, mixed-type arithmetic operators lead to +undesirable behavior in common expressions when combined with literal +type inference. Consider the following example: +```swift +let a: Double = 1 +let b = 2*a +``` +If we had a heterogeneous `*` operator defined, then if there's no prevailing +type context (i.e. we aren't in an extension on some type), the expression +`2*a` is ambiguous; `2` could be either a `Double` or `Complex`. In +a `Complex` context, the situation is even worse: `2*a` is inferred to have +type `Complex`. + +Therefore, the `Complex` type does not have these operators. In order to write +the example from C above, you would use an explicit conversion: +```swift +import ComplexModule +let r = 1.0 +let z = Complex(0, 2) +let w = Complex(r) + z +``` diff --git a/Sources/ComplexModule/Documentation.docc/Infinity.md b/Sources/ComplexModule/Documentation.docc/Infinity.md new file mode 100644 index 00000000..27c16f4a --- /dev/null +++ b/Sources/ComplexModule/Documentation.docc/Infinity.md @@ -0,0 +1,48 @@ +# Zero and infinity + +Semantics of `Complex` zero and infinity values, and important considerations +when porting code from other languages. + +Unlike C and C++'s complex types, `Complex` does not attempt to make a +semantic distinction between different infinity and NaN values. Any `Complex` +datum with a non-finite component is treated as the "point at infinity" on +the Riemann sphere--a value with infinite magnitude and unspecified phase. + +As a consequence, all values with either component infinite or NaN compare +equal, and hash the same. Similarly, all zero values compare equal and hash +the same. + +## Rationale + +This decision has some drawbacks,¹ but also some significant advantages. +In particular, complex multiplication is one of the most common operations with +a complex type, and one would like to be able to use the usual naive arithmetic +implementation, consisting of four real multiplications and two real additions: +``` +(a + bi) * (c + di) = (ac - bd) + (ad + bc)i +``` +`Complex` can use this implementation, because we do not differentiate between +infinities and NaN values. C and C++, by contrast, cannot use this +implementation by default, because, for example: +``` +(1 + ∞i) * (0 - 2i) = (1*0 - ∞*(-2)) + (1*(-2) + ∞*0)i + = (0 - ∞) + (-2 + nan)i + = -∞ + nan i +``` +`Complex` treats this as "infinity", which is the correct result. C and C++ +treat it as a nan value, however, which is incorrect; infinity multiplied +by a non-zero number should be infinity. Thus, C and C++ (by default) must +detect these special cases and fix them up, which makes multiplication a +more computationally expensive operation.² + +### Footnotes: +¹ W. Kahan, Branch Cuts for Complex Elementary Functions, or Much Ado +About Nothing's Sign Bit. In A. Iserles and M.J.D. Powell, editors, +_Proceedings The State of Art in Numerical Analysis_, pages 165–211, 1987. + +² This can be addressed in C programs by use of the `STDC CX_LIMITED_RANGE` +pragma, which instructs the compiler to simply not care about these cases. +Unfortunately, this pragma is not often used in real C or C++ programs +(though it does see some use in _libraries_). Programmers tend to specify +`-ffast-math` or maybe `-ffinite-math-only` instead, which has other +undesirable consequences. diff --git a/Sources/ComplexModule/Documentation.docc/Magnitude.md b/Sources/ComplexModule/Documentation.docc/Magnitude.md new file mode 100644 index 00000000..68f239bd --- /dev/null +++ b/Sources/ComplexModule/Documentation.docc/Magnitude.md @@ -0,0 +1,137 @@ +# Magnitude and norms + +Introduction to the concept of norm and discussion of the `Complex` type's +`.magnitude` property. + +In mathematics, a *norm* is a function that gives each element of a vector +space a non-negative length.¹ + +Many different norms can be defined on the complex numbers, viewed as a +vector space over the reals. All of these norms have some basic +properties. If we use *‖z‖* to represent any norm of *z*, it must: +- be *subadditive* (a.k.a. satisfy the triangle inequalty): + ‖z + w‖ ≤ ‖z‖ + ‖w‖ for any two complex numbers z and w. +- be *homogeneous* + ‖az‖ = |a|‖z‖ for any real number a and complex number z. +- and be *positive definite* + ‖z‖ is zero if and only if z is zero. + +The three most commonly-used norms are: +- 1-norm ("taxicab norm"): + ‖x + iy‖₁ = |x| + |y| +- 2-norm ("Euclidean norm"): + ‖x + iy‖₂ = √(x² + y²) +- ∞-norm ("maximum norm" or "Чебышёв [Chebyshev] norm")²: + ‖x + iy‖ = max(|x|,|y|) + +> Exercise: +> 1. Check that these properties hold for one of the three norms + that we just defined. (Hint: write z = a+bi and w = c+di, + and use the fact that the absolute value is a norm on the + real numbers, and therefore has the same property). + +The `Complex` type gives special names to two of these norms; `length` +for the 2-norm, and `magnitude` for the ∞-norm. + +## Magnitude: + +The `Numeric` protocol requires us to choose a norm to call `magnitude`, +but does not give guidance as to which one we should pick. The easiest choice +might have been the Euclidean norm; it's the one with which people are most +likely to be familiar. + +However, there are good reasons to make a different choice: +- Computing the Euclidean norm requires special care to avoid spurious + overflow/underflow (see implementation notes for `length` below). The + naive expressions for the taxicab and maximum norm always give the best + answer possible. +- Even when special care is used, the Euclidean and taxicab norms are + not necessarily representable. Both can be infinite even for finite + numbers. + ```swift + let big = Double.greatestFiniteMagnitude + let z = Complex(big, big) + ``` + The taxicab norm of `z` would be `big + big`, which overflows; the + Euclidean norm would be `sqrt(2) * big`, which also overflows. + + But the maximum norm is always equal to the magnitude of either `real` + or `imaginary`, so it is necessarily representable if `z` is finite. +- The ∞-norm is the choice of established computational libraries, like + BLAS and LAPACK. + +For these reasons, the `magnitude` property of `Complex` binds the +maximum norm: +```swift +Complex(2, 3).magnitude // 3 +Complex(-1, 0.5).magnitude // 1 +``` + +## Length: + +The `length` property of a `Complex` value is its Euclidean norm. + +```swift +Complex(2, 3).length // 3.605551275463989 +Complex(-1, 0.5).length // 1.118033988749895 +``` + +Aside from familiarity, the Euclidean norm has one important property +that the maximum norm lacks: +- it is *multiplicative*: + ‖zw‖₂ = ‖z‖₂‖w‖₂ for any two complex numbers z and w. + +> Exercises: +> 1. Why isn't the maximum norm multiplicative? + (Hint: Let `z = Complex(1,1)`, and consider `z*z`.) +> 2. Is the 1-norm multiplicative? + +### Implementation notes: + +The `length` property takes special care to produce an accurate answer, +even when the value is poorly-scaled. The naive expression for `length` +would be `sqrt(x*x + y*y)`, but this can overflow or underflow even when +the final result should be a finite number. +```swift +// Suppose that length were implemented like this: +extension Complex { + var naiveLength: RealType { + .sqrt(real*real + imaginary*imaginary) + } +} + +// Then taking the length of even a modestly large number: +let z = Complex(1e20, 1e20) +// or small number: +let w = Complex(1e-24, 1e-24) +// would overflow: +z.naiveLength // Inf +// or underflow: +w.naiveLength // 0 +``` +Instead, `length` is implemented using a two-step algorithm. First we +compute `lengthSquared`, which is `x*x + y*y`. If this is a normal +number (meaning that no overflow or underflow has occured), we can safely +return its square root. Otherwise, we redo the computation with a more +careful computation, which avoids spurious under- or overflow: +```swift +let z = Complex(1e20, 1e20) +let w = Complex(1e-24, 1e-24) +z.length // 1.41421358E+20 +w.length // 1.41421362E-24 +``` + +### Footnotes: + +¹ Throughout this documentation, "norm" refers to a + [vector norm](https://en.wikipedia.org/wiki/Norm_(mathematics)). + To confuse the matter, there are several similar things also called + "norm" in mathematics. The other one you are most likely to run into + is the [field norm](https://en.wikipedia.org/wiki/Field_norm). + + Field norms are much less common than vector norms, but the C++ + `std::norm` operation implements a field norm. To get the (Euclidean) + vector norm in C++, use `std::abs`. + +² There's no subscript-∞ in unicode, so I write the infinity norm + without the usual subscript. diff --git a/Sources/RealModule/Documentation.docc/Augmented.md b/Sources/RealModule/Documentation.docc/Augmented.md new file mode 100644 index 00000000..35987015 --- /dev/null +++ b/Sources/RealModule/Documentation.docc/Augmented.md @@ -0,0 +1,20 @@ +# ``Augmented`` + +## Overview + +Consider multiplying two Doubles. A Double has 53 significand bits, so their +product could be up to 106 bits wide before it is rounded to a Double result. +So up to 53 of those 106 bits will be "lost" in that process: +```swift +let a = 1.0 + .ulpOfOne // 1 + 2⁻⁵² +let b = 1.0 - .ulpOfOne // 1 - 2⁻⁵² +let c = a * b // 1 - 2⁻¹⁰⁴ before rounding, rounds to 1.0 +``` +Sometimes it is necessary to preserve some or all of those low-order bits; +maybe a subsequent subtraction cancels most of the high-order bits, and so +the low-order part of the product suddenly becomes significant: +```swift +let result = 1 - c // exactly zero, but "should be" 2⁻¹⁰⁴ +``` +Augmented arithmetic is a building-block that library writers can use to +handle cases like this more carefully. diff --git a/Sources/RealModule/Documentation.docc/RealModule.md b/Sources/RealModule/Documentation.docc/RealModule.md new file mode 100644 index 00000000..7ffdfdc7 --- /dev/null +++ b/Sources/RealModule/Documentation.docc/RealModule.md @@ -0,0 +1,13 @@ +# ``RealModule`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` diff --git a/Sources/RealModule/Documentation.docc/Relaxed.md b/Sources/RealModule/Documentation.docc/Relaxed.md new file mode 100644 index 00000000..a7a5cacb --- /dev/null +++ b/Sources/RealModule/Documentation.docc/Relaxed.md @@ -0,0 +1,46 @@ +# ``Relaxed`` + +## Overview + +Because of rounding, and the arithmetic rules for infinity and NaN values, +floating-point addition and multiplication are not associative: +```swift +let ε = Double.leastNormalMagnitude +let sumLeft = (-1 + 1) + ε // 0 + ε = ε +let sumRight = -1 + (1 + ε) // -1 + 1 = 0 + +let ∞ = Double.infinity +let productLeft = (ε * ε) * ∞ // 0 * ∞ = .nan +let productRight = ε * (ε * ∞) // ε * ∞ = ∞ +``` +For some algorithms, the distinction between these results is incidental; for +some others it is critical to their correct function. Because of this, +compilers cannot freely change the order of reductions, which prevents some +important optimizations: extraction of instruction-level parallelism and +vectorization. + +If you know that you are in a case where the order of elements being summed +or multiplied is incidental, the Relaxed operations give you a mechanism +to communicate that to the compiler and unlock these optimizations. For +example, consider the following two functions: +```swift +func sum(array: [Float]) -> Float { + array.reduce(0, +) +} + +func relaxedSum(array: [Float]) -> Float { + array.reduce(0, Relaxed.sum) +} +``` +when called on an array with 1000 elements in a Release build, `relaxedSum` +is about 8x faster than `sum` on Apple M2, with a similar speedup on Intel +processors, without the need for any unsafe code or flags. + +### multiplyAdd + +In addition to `Relaxed.sum` and `Relaxed.product`, `Relaxed` provides the +``multiplyAdd(_:_:_:)`` operation, which communciates to the compiler that +it is allowed to replace separate multiply and add operations with a single +_fused multiply-add_ instruction if its cost model indicates that it would +be advantageous to do so. When targeting processors that support this +instruction, this may be a significant performance advantage. From 129e496ef17c588a1ff957e607f7f92d9ebab3b7 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 17 Jul 2023 16:17:51 -0400 Subject: [PATCH 02/19] Further docc work. --- Sources/ComplexModule/Complex.swift | 53 +++++++++++------------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/Sources/ComplexModule/Complex.swift b/Sources/ComplexModule/Complex.swift index aa3f2609..88133e9d 100644 --- a/Sources/ComplexModule/Complex.swift +++ b/Sources/ComplexModule/Complex.swift @@ -11,39 +11,11 @@ import RealModule -/// A complex number represented by real and imaginary parts. +/// A [complex number](https://en.wikipedia.org/wiki/Complex_number). /// -/// TODO: introductory text on complex numbers -/// -/// Implementation notes: -/// -/// This type does not provide heterogeneous real/complex arithmetic, -/// not even the natural vector-space operations like real * complex. -/// There are two reasons for this choice: first, Swift broadly avoids -/// mixed-type arithmetic when the operation can be adequately expressed -/// by a conversion and homogeneous arithmetic. Second, with the current -/// typechecker rules, it would lead to undesirable ambiguity in common -/// expressions (see README.md for more details). -/// -/// Unlike C's `_Complex` and C++'s `std::complex<>` types, we do not -/// attempt to make meaningful semantic distinctions between different -/// representations of infinity or NaN. Any Complex value with at least -/// one non-finite component is simply "non-finite". In as much as -/// possible, we use the semantics of the point at infinity on the -/// Riemann sphere for such values. This approach simplifies the number of -/// edge cases that need to be considered for multiplication, division, and -/// the elementary functions considerably. -/// -/// `.magnitude` does not return the Euclidean norm; it uses the "infinity -/// norm" (`max(|real|,|imaginary|)`) instead. There are two reasons for this -/// choice: first, it's simply faster to compute on most hardware. Second, -/// there exist values for which the Euclidean norm cannot be represented -/// (consider a number with `.real` and `.imaginary` both equal to -/// `RealType.greatestFiniteMagnitude`; the Euclidean norm would be -/// `.sqrt(2) * .greatestFiniteMagnitude`, which overflows). Using -/// the infinity norm avoids this problem entirely without significant -/// downsides. You can access the Euclidean norm using the `length` -/// property. +/// `Complex` is an `AlgebraicField`, so it has all the normal arithmetic +/// operators. It conforms to `ElementaryFunctions`, so it has all the usual +/// math functions. @frozen public struct Complex where RealType: Real { // A note on the `x` and `y` properties @@ -53,11 +25,11 @@ public struct Complex where RealType: Real { // `.real` and `.imaginary` properties, which wrap this storage and // fixup the semantics for non-finite values. - /// The real component of the value. + /// The storage for the real component of the value. @usableFromInline @inline(__always) internal var x: RealType - /// The imaginary part of the value. + /// The storage for the imaginary part of the value. @usableFromInline @inline(__always) internal var y: RealType @@ -95,11 +67,24 @@ extension Complex { set { y = newValue } } + /// The raw representation of the value. + /// + /// Use this when you need the underlying RealType values, + /// without fixup for NaN or infinity. + public var rawStorage: (x: RealType, y: RealType) { + @_transparent + get { (x, y) } + @_transparent + set { (x, y) = newValue } + } + /// The raw representation of the real part of this value. + @available(*, deprecated, message: "Use rawStorage") @_transparent public var _rawX: RealType { x } /// The raw representation of the imaginary part of this value. + @available(*, deprecated, message: "Use rawStorage") @_transparent public var _rawY: RealType { y } } From d2f6811b87ff329f129e23fb260208b77e23cb7a Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 17 Jul 2023 16:23:39 -0400 Subject: [PATCH 03/19] More docc changes. --- Sources/ComplexModule/Complex+Numeric.swift | 16 +++--- .../Documentation.docc/Infinity.md | 9 ++-- Sources/ComplexModule/Polar.swift | 21 ++++---- Sources/ComplexModule/Scale.swift | 37 +++++-------- .../IntegerUtilities/DivideWithRounding.swift | 53 ++++++++++--------- .../SaturatingArithmetic.swift | 20 +++---- .../IntegerUtilities/ShiftWithRounding.swift | 8 +-- Sources/RealModule/AlgebraicField.swift | 2 +- Sources/RealModule/AugmentedArithmetic.swift | 7 +-- Sources/RealModule/ElementaryFunctions.swift | 2 +- Sources/RealModule/Real.swift | 25 ++++----- 11 files changed, 96 insertions(+), 104 deletions(-) diff --git a/Sources/ComplexModule/Complex+Numeric.swift b/Sources/ComplexModule/Complex+Numeric.swift index 751640c7..8ec7d273 100644 --- a/Sources/ComplexModule/Complex+Numeric.swift +++ b/Sources/ComplexModule/Complex+Numeric.swift @@ -37,14 +37,18 @@ extension Complex: Numeric { self.init(real, 0) } - /// The ∞-norm of the value (`max(abs(real), abs(imaginary))`). + /// The infinity-norm of the value (a.k.a. "maximum norm" or "Чебышёв norm"). /// - /// If you need the Euclidean norm (a.k.a. 2-norm) use the `length` or - /// `lengthSquared` properties instead. + /// Equal to `max(abs(real), abs(imaginary))`. /// - /// Edge cases: - /// - If `z` is not finite, `z.magnitude` is `.infinity`. - /// - If `z` is zero, `z.magnitude` is `0`. + /// If you need to work with the Euclidean norm (a.k.a. 2-norm) instead, + /// use the `length` or `lengthSquared` properties. If you just need to + /// know "how big" a number is, use this property. + /// + /// **Edge cases:** + /// + /// - If `z` is not finite, `z.magnitude` is infinity. + /// - If `z` is zero, `z.magnitude` is zero. /// - Otherwise, `z.magnitude` is finite and non-zero. /// /// See also `.length` and `.lengthSquared`. diff --git a/Sources/ComplexModule/Documentation.docc/Infinity.md b/Sources/ComplexModule/Documentation.docc/Infinity.md index 27c16f4a..2f713f5a 100644 --- a/Sources/ComplexModule/Documentation.docc/Infinity.md +++ b/Sources/ComplexModule/Documentation.docc/Infinity.md @@ -14,10 +14,11 @@ the same. ## Rationale -This decision has some drawbacks,¹ but also some significant advantages. -In particular, complex multiplication is one of the most common operations with -a complex type, and one would like to be able to use the usual naive arithmetic -implementation, consisting of four real multiplications and two real additions: +This choice has some drawbacks,¹ but also some significant advantages. +In particular, complex multiplication is the most common operation performed +with a complex type, and one would like to be able to use the usual naive +arithmetic implementation, consisting of four real multiplications and two +real additions: ``` (a + bi) * (c + di) = (ac - bd) + (ad + bc)i ``` diff --git a/Sources/ComplexModule/Polar.swift b/Sources/ComplexModule/Polar.swift index ecdd878c..3a7587a8 100644 --- a/Sources/ComplexModule/Polar.swift +++ b/Sources/ComplexModule/Polar.swift @@ -12,7 +12,7 @@ import RealModule extension Complex { - /// The Euclidean norm (a.k.a. 2-norm, `sqrt(real*real + imaginary*imaginary)`). + /// The Euclidean norm (a.k.a. 2-norm). /// /// This property takes care to avoid spurious over- or underflow in /// this computation. For example: @@ -28,7 +28,7 @@ extension Complex { /// /// For most use cases, you can use the cheaper `.magnitude` /// property (which computes the ∞-norm) instead, which always produces - /// a representable result. + /// a representable result. See for more details. /// /// Edge cases: /// - If a complex value is not finite, its `.length` is `infinity`. @@ -63,25 +63,24 @@ extension Complex { /// For many cases, `.magnitude` can be used instead, which is similarly /// cheap to compute and always returns a representable value. /// - /// See also `.length` and `.magnitude`. + /// Note that because of how `lengthSquared` is used, it is a primary + /// design goal that it be as fast as possible. Therefore, it does not + /// normalize infinities, and may return either `.infinity` or `.nan` + /// for non-finite values. + /// + /// See also ``length`` and ``magnitude``. @_transparent public var lengthSquared: RealType { x*x + y*y } - @available(*, unavailable, renamed: "lengthSquared") - public var unsafeLengthSquared: RealType { lengthSquared } - /// The phase (angle, or "argument"). /// - /// Returns the angle (measured above the real axis) in radians. If + /// - Returns: The angle (measured above the real axis) in radians. If /// the complex value is zero or infinity, the phase is not defined, /// and `nan` is returned. /// - /// Edge cases: - /// - If the complex value is zero or non-finite, phase is `nan`. - /// - /// See also `.length`, `.polar` and `init(r:θ:)`. + /// See also ``length``, ``polar`` and ``init(length:phase:)``. @inlinable public var phase: RealType { guard isFinite && !isZero else { return .nan } diff --git a/Sources/ComplexModule/Scale.swift b/Sources/ComplexModule/Scale.swift index 57237702..b7ac7780 100644 --- a/Sources/ComplexModule/Scale.swift +++ b/Sources/ComplexModule/Scale.swift @@ -20,35 +20,22 @@ // what is the type of b? If we don't have a type context, it's ambiguous. // If we have a Complex type context, then b will be inferred to have type // Complex! Obviously, that doesn't help anyone. -// -// TODO: figure out if there's some way to avoid these surprising results -// and turn these into operators if/when we have it. -// (https://github.com/apple/swift-numerics/issues/12) + extension Complex { - /// `self` scaled by `a`. - @usableFromInline @_transparent - internal func multiplied(by a: RealType) -> Complex { - // This can be viewed in two different ways, which are mathematically - // equivalent: either we are computing `self * Complex(a)` (i.e. - // converting `a` to be a complex value, and then using the complex - // multiplication) or we are using the scalar product of the vector - // space structure: `Complex(a*real, a*imaginary)`. - // - // Although these two interpretations are _mathematically_ equivalent, - // they will generate different representations of the point at - // infinity in general. For example, suppose `self` is represented by - // `(infinity, 0)`. Then `self * Complex(1)` would evaluate as - // `(1*infinity - 0*0, 0*infinity + 1*0) = (infinity, nan)`, but - // the vector space interpretation produces `(infinity, 0)`. This does - // not matter much, because these are two representations of the same - // semantic value, but note that one requires four multiplies and two - // additions, while the one we use requires only two real multiplications. + /// `self` multiplied by the real value `a`. + /// + /// Equivalent to `self * Complex(a)`, but may be computed more efficiently. + @inlinable @inline(__always) + public func multiplied(by a: RealType) -> Complex { Complex(x*a, y*a) } - /// `self` unscaled by `a`. - @usableFromInline @_transparent - internal func divided(by a: RealType) -> Complex { + /// `self` divided by the real value `a`. + /// + /// More efficient than `self / Complex(a)`. May not produce exactly the + /// same result, but will always be more accurate when they differ. + @inlinable @inline(__always) + public func divided(by a: RealType) -> Complex { // See implementation notes for `multiplied` above. Complex(x/a, y/a) } diff --git a/Sources/IntegerUtilities/DivideWithRounding.swift b/Sources/IntegerUtilities/DivideWithRounding.swift index caf0b177..1426c008 100644 --- a/Sources/IntegerUtilities/DivideWithRounding.swift +++ b/Sources/IntegerUtilities/DivideWithRounding.swift @@ -12,26 +12,29 @@ extension BinaryInteger { /// `self` divided by `other`, rounding the result according to `rule`. /// - /// The default rounding rule is `.down`, which _is not the same_ as the - /// behavior of the `/` operator from the Swift standard library, but is - /// chosen because it generally produces a more useful remainder. In - /// particular, when `b` is positive, the remainder is always positive. - /// To match the behavior of `/`, use the `.towardZero` rounding mode. + /// By default, this function uses ``RoundingRule/down``, which **is not + /// the same** as the rounding of the `/` operator from the Swift standard + /// library. They agree when the signs of the arguments match, but produce + /// different results when the quotient is negative. This behavior is + /// chosen because it generally produces a more useful remainder; in + /// particular, when the divisor is positive, the remainder is always + /// positive. To match the behavior of `/`, use ``RoundingRule/towardZero``. /// /// Note that the remainder of division is not always representable in an - /// unsigned type if a rounding rule other than `.down`, `.towardZero`, or - /// `.requireExact` is used. For example: - /// - /// let a: UInt = 5 - /// let b: UInt = 3 - /// let q = a.divided(by: b, rounding: .up) // 2 - /// let r = a - b*q // 5 - 3*2 overflows UInt. - /// + /// unsigned type if a rounding rule other than ``RoundingRule/down``, + /// ``RoundingRule/towardZero``, or ``RoundingRule/requireExact`` is + /// used. For example: + /// ```swift + /// let a: UInt = 5 + /// let b: UInt = 3 + /// let q = a.divided(by: b, rounding: .up) // 2 + /// let r = a - b*q // 5 - 3*2 overflows UInt. + /// ``` /// For this reason, there is no `remainder(dividingBy:rounding:)` /// operation defined on `BinaryInteger`. Signed integers do not have - /// this problem, so it is defined on the `SignedInteger` protocol - /// instead, as is an overload of `divided(by:rounding:)` that returns - /// both quotient and remainder. + /// this problem, so the `SignedInteger` protocol is extended with + /// ``SignedInteger/divided(by:rounding:)`` returning both quotient + /// and remainder. @inlinable public func divided( by other: Self, @@ -52,7 +55,7 @@ extension BinaryInteger { // rounded toward zero. // // If we subtract 1 from q, we add other to r to compensate, because: - // + // // self = q*other + r // = (q-1)*other + (r+other) // @@ -151,10 +154,10 @@ extension SignedInteger { /// Divides `self` by `other`, rounding the quotient according to `rule`, /// and returns the remainder. /// - /// The default rounding rule is `.down`, which _is not the same_ as the - /// behavior of the `%` operator from the Swift standard library, but is - /// chosen because it generally produces a more useful remainder. To - /// match the behavior of `%`, use the `.towardZero` rounding mode. + /// The default rounding rule is ``RoundingRule/down``, which _is not the + /// same_ as the behavior of the `%` operator from the Swift standard + /// library, but is chosen because it generally produces a more useful + /// remainder. To match the behavior of `%`, use ``RoundingRule/towardZero``. /// /// - Precondition: `other` cannot be zero. @inlinable @@ -170,10 +173,10 @@ extension SignedInteger { /// Divides `self` by `other`, rounding the quotient according to `rule`, /// and returns both the quotient and remainder. /// - /// The default rounding rule is `.down`, which _is not the same_ as the - /// behavior of the `/` operator from the Swift standard library, but is - /// chosen because it generally produces a more useful remainder. To - /// match the behavior of `/`, use the `.towardZero` rounding mode. + /// The default rounding rule is ``RoundingRule/down``, which _is not the + /// same_ as the behavior of the `%` operator from the Swift standard + /// library, but is chosen because it generally produces a more useful + /// remainder. To match the behavior of `/`, use ``RoundingRule/towardZero``. /// /// Because the default rounding mode does not match Swift's standard /// library, this function is a disfavored overload of `divided(by:)` diff --git a/Sources/IntegerUtilities/SaturatingArithmetic.swift b/Sources/IntegerUtilities/SaturatingArithmetic.swift index 7c001608..94c9e43c 100644 --- a/Sources/IntegerUtilities/SaturatingArithmetic.swift +++ b/Sources/IntegerUtilities/SaturatingArithmetic.swift @@ -31,8 +31,8 @@ extension FixedWidthInteger { /// let c = a.addingWithSaturation(b) /// ``` /// - /// Anytime the "normal addition" `self + other` does not trap, - /// `addingWithSaturation` produces the same result. + /// If the "normal addition" `self + other` does not trap, + /// this method produces the same result. @inlinable public func addingWithSaturation(_ other: Self) -> Self { let (wrapped, overflow) = addingReportingOverflow(other) @@ -54,8 +54,8 @@ extension FixedWidthInteger { /// `a.subtractingWithSaturation(b)`, because `-b` is not representable /// if `b` is the minimum value of a signed type. /// - /// Anytime the "normal subtraction" `self - other` does not trap, - /// `subtractingWithSaturation` produces the same result. + /// If the "normal subtraction" `self - other` does not trap, + /// this method produces the same result. @inlinable public func subtractingWithSaturation(_ other: Self) -> Self { let (wrapped, overflow) = subtractingReportingOverflow(other) @@ -85,8 +85,8 @@ extension FixedWidthInteger { /// let c = a.multipliedWithSaturation(by: b) /// ``` /// - /// Anytime the "normal multiplication" `self * other` does not trap, - /// `multipliedWithSaturation` produces the same result. + /// If the "normal multiplication" `self * other` does not trap, + /// this method produces the same result. @inlinable public func multipliedWithSaturation(by other: Self) -> Self { let (high, low) = multipliedFullWidth(by: other) @@ -100,12 +100,12 @@ extension FixedWidthInteger { /// `self` multiplied by the rational number 2^(`count`), saturated to the /// range `Self.min ... Self.max`, and rounded according to `rule`. /// - /// See `shifted(rightBy:rounding:)` for more discussion of rounding - /// shifts with examples. + /// See `shifted(rightBy:rounding:)`, defined on `BinaryInteger`, for more + /// discussion of rounding shifts with examples. /// /// - Parameters: - /// - leftBy count: the number of bits to shift by. If positive, this is a left-shift, - /// and if negative a right shift. + /// - leftBy count: the number of bits to shift by. If positive, this is + /// a left-shift, and if negative a right shift. /// - rounding rule: the direction in which to round if `count` is negative. @inlinable public func shiftedWithSaturation( diff --git a/Sources/IntegerUtilities/ShiftWithRounding.swift b/Sources/IntegerUtilities/ShiftWithRounding.swift index b83f1e64..cc2f412f 100644 --- a/Sources/IntegerUtilities/ShiftWithRounding.swift +++ b/Sources/IntegerUtilities/ShiftWithRounding.swift @@ -12,8 +12,8 @@ extension BinaryInteger { /// `self` divided by 2^(`count`), rounding the result according to `rule`. /// - /// The default rounding rule is `.down`, which matches the behavior of - /// the `>>` operator from the standard library. + /// The default rounding rule is ``RoundingRule/down``, which matches the + /// behavior of the `>>` operator from the standard library. /// /// Some examples of different rounding rules: /// @@ -138,8 +138,8 @@ extension BinaryInteger { /// `self` divided by 2^(`count`), rounding the result according to `rule`. /// - /// The default rounding rule is `.down`, which matches the behavior of - /// the `>>` operator from the standard library. + /// The default rounding rule is ``RoundingRule/down``, which matches the + /// behavior of the `>>` operator from the standard library. /// /// Some examples of different rounding rules: /// diff --git a/Sources/RealModule/AlgebraicField.swift b/Sources/RealModule/AlgebraicField.swift index 4c8070db..230187b8 100644 --- a/Sources/RealModule/AlgebraicField.swift +++ b/Sources/RealModule/AlgebraicField.swift @@ -40,7 +40,7 @@ /// See also `Real`, `SignedNumeric`, `Numeric` and `AdditiveArithmetic`. /// /// [field]: https://en.wikipedia.org/wiki/Field_(mathematics) -public protocol AlgebraicField: SignedNumeric { +public protocol AlgebraicField: SignedNumeric where Magnitude: AlgebraicField { /// Replaces a with the (approximate) quotient `a/b`. static func /=(a: inout Self, b: Self) diff --git a/Sources/RealModule/AugmentedArithmetic.swift b/Sources/RealModule/AugmentedArithmetic.swift index 2e953673..4cd8f4b4 100644 --- a/Sources/RealModule/AugmentedArithmetic.swift +++ b/Sources/RealModule/AugmentedArithmetic.swift @@ -9,11 +9,8 @@ // //===----------------------------------------------------------------------===// -/// A namespace for "augmented arithmetic" operations for types conforming to -/// `Real`. -/// -/// Augmented arithmetic refers to a family of algorithms that represent -/// the results of floating-point computations using multiple values such that +/// Augmented arithmetic provides a family of algorithms that represent the +/// results of floating-point computations using multiple values such that /// either the error is minimized or the result is exact. public enum Augmented { } diff --git a/Sources/RealModule/ElementaryFunctions.swift b/Sources/RealModule/ElementaryFunctions.swift index 7e355ec7..0b8ccf4e 100644 --- a/Sources/RealModule/ElementaryFunctions.swift +++ b/Sources/RealModule/ElementaryFunctions.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -/// A type that has elementary functions available. +/// A type that has elementary functions (`sin`, `cos`, etc.) available. /// /// An ["elementary function"][elfn] is a function built up from powers, roots, /// exponentials, logarithms, trigonometric functions (sin, cos, tan) and diff --git a/Sources/RealModule/Real.swift b/Sources/RealModule/Real.swift index ec363df1..fff6c885 100644 --- a/Sources/RealModule/Real.swift +++ b/Sources/RealModule/Real.swift @@ -24,18 +24,19 @@ /// } /// ``` /// See also `ElementaryFunctions`, `RealFunctions` and `AlgebraicField`. -public protocol Real: FloatingPoint, RealFunctions, AlgebraicField { -} +public protocol Real: FloatingPoint, RealFunctions, AlgebraicField { } // While `Real` does not provide any additional customization points, // it does allow us to default the implementation of a few operations, // and also provides `signGamma`. extension Real { // Most math libraries do not provide exp10, so we need a default - // implementation. + // implementation. This is not a great one (if the underlying math + // library does not have a sub-ulp accurate pow, this will not get + // exact powers of ten right), but suffices in the short term. @_transparent public static func exp10(_ x: Self) -> Self { - return pow(10, x) + pow(10, x) } /// cos(x) - 1, computed in such a way as to maintain accuracy for small x. @@ -90,7 +91,7 @@ extension Real { @_transparent public static func sqrt(_ x: Self) -> Self { - return x.squareRoot() + x.squareRoot() } /// The (approximate) reciprocal (multiplicative inverse) of this number, @@ -128,13 +129,13 @@ extension Real { /// the real reciprocal (when it exists) as follows (I will use circle /// operators to denote real-number arithmetic, and normal operators /// for floating-point arithmetic): - /// - /// a * b.reciprocal! = a * (1/b) - /// = a * (1 ⊘ b)(1 + δ₁) - /// = (a ⊘ b)(1 + δ₁)(1 + δ₂) - /// = (a ⊘ b)(1 + δ₁ + δ₂ + δ₁δ₂) - /// - /// where 0 < δᵢ <= ulpOfOne/2. This gives a roughly 1-ulp error, + /// ``` + /// a * b.reciprocal! = a * (1/b) + /// = a * (1 ⊘ b)(1 + δ₁) + /// = (a ⊘ b)(1 + δ₁)(1 + δ₂) + /// = (a ⊘ b)(1 + δ₁ + δ₂ + δ₁δ₂) + /// ``` + /// where `0 < δᵢ <= ulpOfOne/2`. This gives a roughly 1-ulp error, /// about twice the error bound we get using division. For most /// purposes this is an acceptable error, but if you need to match /// results obtained using division, you should not use this. From 95e9441f8cff7531cce4d8b29c5425ffde20c7ea Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 18 Jul 2023 17:21:16 -0400 Subject: [PATCH 04/19] Changes from review feedback. --- .../Documentation.docc/Complex.md | 4 ++ .../Documentation.docc/ComplexModule.md | 47 ++++++++++++------- .../Documentation.docc/Infinity.md | 4 ++ .../Documentation.docc/Magnitude.md | 2 + 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index 63c389b4..62395fa7 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -6,20 +6,24 @@ A `Complex` value is represented with two `RealType` values, corresponding to the real and imaginary parts of the number: + ```swift let z = Complex(1,-1) // 1 - i let re = z.real // 1 let im = z.imaginary // -1 ``` + All `Complex` numbers with a non-finite component is treated as a single "point at infinity," with infinite magnitude and indeterminant phase. Thus, the real and imaginary parts of an infinity are nan. + ```swift let w = Complex.infinity w == -w // true let re = w.real // .nan let im = w.imag // .nan ``` + See for more details. - ``init(_:_:)`` diff --git a/Sources/ComplexModule/Documentation.docc/ComplexModule.md b/Sources/ComplexModule/Documentation.docc/ComplexModule.md index e1cd6c8a..23c13244 100644 --- a/Sources/ComplexModule/Documentation.docc/ComplexModule.md +++ b/Sources/ComplexModule/Documentation.docc/ComplexModule.md @@ -7,6 +7,7 @@ Types and operations for working with complex numbers. The `Complex` type is generic over an associated `RealType`; complex numbers are represented as two `RealType` values, the real and imaginary parts of the number. + ``` let z = Complex(1, 2) let re = z.real @@ -32,32 +33,42 @@ map them into Swift types by converting pointers. Because the real numbers are a subset of the complex numbers, many languages support arithmetic with mixed real and complex operands. For example, C allows the following: + ```c #include double r = 1; double complex z = CMPLX(0, 2); // 2i double complex w = r + z; // 1 + 2i ``` -The `Complex` type does not provide such mixed operators. There are two -reasons for this choice. First, Swift generally avoids mixed-type -arithmetic, period. Second, mixed-type arithmetic operators lead to -undesirable behavior in common expressions when combined with literal -type inference. Consider the following example: + +The `Complex` type does not provide such mixed operators: + ```swift -let a: Double = 1 -let b = 2*a +let r = 1.0 +let z = Complex(imaginary: 2.0) +let w = r + z // error: binary operator '+' cannot be applied to operands of type 'Double' and 'Complex' ``` -If we had a heterogeneous `*` operator defined, then if there's no prevailing -type context (i.e. we aren't in an extension on some type), the expression -`2*a` is ambiguous; `2` could be either a `Double` or `Complex`. In -a `Complex` context, the situation is even worse: `2*a` is inferred to have -type `Complex`. - -Therefore, the `Complex` type does not have these operators. In order to write -the example from C above, you would use an explicit conversion: + +In order to write the example from C above in Swift, you have to perform an +explicit conversion: + ```swift -import ComplexModule let r = 1.0 -let z = Complex(0, 2) -let w = Complex(r) + z +let z = Complex(imaginary: 2.0) +let w = Complex(r) + z // OK +``` + +There are two reasons for this choice. Most importantly, Swift generally avoids +mixed-type arithmetic. Second, if we _did_ provide such heterogeneous operators, +it would lead to undesirable behavior in common expressions when combined with +literal type inference. Consider the following example: + +```swift +let a: Double = 1 +let b = 2*a ``` + +`b` ought to have type `Double`, but if we did have a Complex-by-Real `*` +operation, `2*a` would either be ambiguous (if there were no type context), +or be inferred to have type `Complex` (if the expression appeared +in the context of an extension defined on `Compex`). diff --git a/Sources/ComplexModule/Documentation.docc/Infinity.md b/Sources/ComplexModule/Documentation.docc/Infinity.md index 2f713f5a..7cd45cb8 100644 --- a/Sources/ComplexModule/Documentation.docc/Infinity.md +++ b/Sources/ComplexModule/Documentation.docc/Infinity.md @@ -19,17 +19,21 @@ In particular, complex multiplication is the most common operation performed with a complex type, and one would like to be able to use the usual naive arithmetic implementation, consisting of four real multiplications and two real additions: + ``` (a + bi) * (c + di) = (ac - bd) + (ad + bc)i ``` + `Complex` can use this implementation, because we do not differentiate between infinities and NaN values. C and C++, by contrast, cannot use this implementation by default, because, for example: + ``` (1 + ∞i) * (0 - 2i) = (1*0 - ∞*(-2)) + (1*(-2) + ∞*0)i = (0 - ∞) + (-2 + nan)i = -∞ + nan i ``` + `Complex` treats this as "infinity", which is the correct result. C and C++ treat it as a nan value, however, which is incorrect; infinity multiplied by a non-zero number should be infinity. Thus, C and C++ (by default) must diff --git a/Sources/ComplexModule/Documentation.docc/Magnitude.md b/Sources/ComplexModule/Documentation.docc/Magnitude.md index 68f239bd..9dd8331a 100644 --- a/Sources/ComplexModule/Documentation.docc/Magnitude.md +++ b/Sources/ComplexModule/Documentation.docc/Magnitude.md @@ -62,6 +62,7 @@ However, there are good reasons to make a different choice: For these reasons, the `magnitude` property of `Complex` binds the maximum norm: + ```swift Complex(2, 3).magnitude // 3 Complex(-1, 0.5).magnitude // 1 @@ -92,6 +93,7 @@ The `length` property takes special care to produce an accurate answer, even when the value is poorly-scaled. The naive expression for `length` would be `sqrt(x*x + y*y)`, but this can overflow or underflow even when the final result should be a finite number. + ```swift // Suppose that length were implemented like this: extension Complex { From 450691764d757328c0a5eb9caee6b846de797188 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 18 Jul 2023 17:23:31 -0400 Subject: [PATCH 05/19] typo. --- Sources/ComplexModule/Documentation.docc/ComplexModule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ComplexModule/Documentation.docc/ComplexModule.md b/Sources/ComplexModule/Documentation.docc/ComplexModule.md index 23c13244..8b6159a1 100644 --- a/Sources/ComplexModule/Documentation.docc/ComplexModule.md +++ b/Sources/ComplexModule/Documentation.docc/ComplexModule.md @@ -71,4 +71,4 @@ let b = 2*a `b` ought to have type `Double`, but if we did have a Complex-by-Real `*` operation, `2*a` would either be ambiguous (if there were no type context), or be inferred to have type `Complex` (if the expression appeared -in the context of an extension defined on `Compex`). +in the context of an extension defined on `Complex`). From 5b34639450de6e393492ddbb03b5487143ec8467 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Thu, 21 Sep 2023 10:58:46 -0400 Subject: [PATCH 06/19] Further documentation work for Complex. --- .../Documentation.docc/Complex.md | 37 ++++--------------- .../Documentation.docc/ComplexModule.md | 12 ++++++ 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index 62395fa7..8b534b88 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -1,8 +1,6 @@ # ``Complex`` -## Topics - -### Real and imaginary parts +## Real and imaginary parts A `Complex` value is represented with two `RealType` values, corresponding to the real and imaginary parts of the number: @@ -13,7 +11,7 @@ let re = z.real // 1 let im = z.imaginary // -1 ``` -All `Complex` numbers with a non-finite component is treated as a single +All `Complex` numbers with a non-finite component are treated as a single "point at infinity," with infinite magnitude and indeterminant phase. Thus, the real and imaginary parts of an infinity are nan. @@ -26,30 +24,9 @@ let im = w.imag // .nan See for more details. -- ``init(_:_:)`` -- ``init(_:)-5aesj`` -- ``init(imaginary:)`` -- ``real`` -- ``imaginary`` - -### Magnitude and norms - -See the article for more details. - -- ``magnitude`` -- ``length`` -- ``lengthSquared`` -- ``normalized`` - -### Polar representations - -- ``init(length:phase:)`` -- ``phase`` -- ``length`` -- ``polar`` - -### Conversions from other types +### Length and magnitude -- ``init(_:)-4csd3`` -- ``init(_:)-80jml`` -- ``init(exactly:)-767k9`` +The ``magnitude`` property of a complex number is the infinity norm of the +value (a.k.a. “maximum norm” or “Чебышёв norm”). To get the two norm (a.k.a +"Euclidean norm"), use the ``length`` property. See for more +details. diff --git a/Sources/ComplexModule/Documentation.docc/ComplexModule.md b/Sources/ComplexModule/Documentation.docc/ComplexModule.md index 8b6159a1..8300f005 100644 --- a/Sources/ComplexModule/Documentation.docc/ComplexModule.md +++ b/Sources/ComplexModule/Documentation.docc/ComplexModule.md @@ -72,3 +72,15 @@ let b = 2*a operation, `2*a` would either be ambiguous (if there were no type context), or be inferred to have type `Complex` (if the expression appeared in the context of an extension defined on `Complex`). + +Note that we _do_ provide heterogeneous multiplication and division by a real +value, spelled as ``Complex/divided(by:)`` and ``Complex/multiplied(by:)`` +to avoid ambiguity. + +```swift +let z = Complex(1,3) +let w = z.multiplied(by: 2) +``` + +These operations are generally more efficient than converting the scale to +a complex number and then using `*` or `/`. From 5cc83cc00a725721f09cad30bb8b1bc5728e4bbc Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Thu, 21 Sep 2023 16:35:35 -0400 Subject: [PATCH 07/19] WIP --- Sources/RealModule/Documentation.docc/RealModule.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Sources/RealModule/Documentation.docc/RealModule.md b/Sources/RealModule/Documentation.docc/RealModule.md index 7ffdfdc7..285655ef 100644 --- a/Sources/RealModule/Documentation.docc/RealModule.md +++ b/Sources/RealModule/Documentation.docc/RealModule.md @@ -1,13 +1,6 @@ # ``RealModule`` -Summary +A module that extends the Swift standard library protocols to provide +additional operations for floating-point types. ## Overview - -Text - -## Topics - -### Group - -- ``Symbol`` From 2361b4959b3605554a67e875f69c351f7122c822 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Fri, 8 Aug 2025 13:43:30 -0400 Subject: [PATCH 08/19] Add overview for RealModule documentation. --- .../Documentation.docc/RealModule.md | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Sources/RealModule/Documentation.docc/RealModule.md b/Sources/RealModule/Documentation.docc/RealModule.md index 285655ef..971b8858 100644 --- a/Sources/RealModule/Documentation.docc/RealModule.md +++ b/Sources/RealModule/Documentation.docc/RealModule.md @@ -1,6 +1,28 @@ # ``RealModule`` -A module that extends the Swift standard library protocols to provide -additional operations for floating-point types. +Extensions on the Swift standard library that provide functionality for +floating-point types. ## Overview + +``RealModule`` provides four protocols that extend the standard library's +numeric protocol hierarchy: AlgebraicField, ElementaryFunctions, +RealFunctions, and Real. + +Types conforming to AlgebraicField represent +[fields](https://en.wikipedia.org/wiki/Field_(mathematics)). These are the +mathematical structures that typically form the elements of vectors and +matrices, so this protocol is appropriate for writing generic code to do +linear-algebra-type operations. + +ElementaryFunctions provides bindings for the "math functions": the logarithm +and exponential functions, sine, cosine and tangent as well as their inverses, +and other functions that you may be familiar with from trigonometry and +calculus. RealFunctions refines ElementaryFunctions and provides functions that +are primarily used with the real numbers, such as atan2, erf and gamma, and +the base-2 and -10 logarithm and exponential funtions. + +The Real protocol is a convenient name for the intersection of `FloatingPoint`, +`RealFunctions`, and `AlgebraicField`; this is the protocol that you are most +likely to want to constrain to when writing generic "math" code that works +with floating-point types. From af0352e8b18103853787b9fbcf05011ead962648 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Sat, 9 Aug 2025 14:29:05 -0400 Subject: [PATCH 09/19] Some additional organization for Complex docc. --- .../Documentation.docc/Complex.md | 45 +++++++++++++++++-- .../Documentation.docc/Magnitude.md | 4 +- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index 8b534b88..b49ae46a 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -1,9 +1,14 @@ # ``Complex`` -## Real and imaginary parts +A Complex number type that conforms to ``AlgebraicField`` (so all the normal +arithmetic operations are available) and ``ElementaryFunctions`` (so all +the usual math functions are available). A `Complex` value is represented with two `RealType` values, corresponding to -the real and imaginary parts of the number: +the real and imaginary parts of the number. + +You can access these Cartesian components using the real and imaginary +properties. ```swift let z = Complex(1,-1) // 1 - i @@ -24,9 +29,41 @@ let im = w.imag // .nan See for more details. -### Length and magnitude - The ``magnitude`` property of a complex number is the infinity norm of the value (a.k.a. “maximum norm” or “Чебышёв norm”). To get the two norm (a.k.a "Euclidean norm"), use the ``length`` property. See for more details. + +## Topics + +### Real and imaginary parts + +- ``real`` +- ``imaginary`` +- ``rawStorage`` +- ``init(_:_:)`` +- ``init(_:)-(RealType)`` +- ``init(imaginary:)`` + +### Phase, length and magnitude + +- ``magnitude`` +- ``length`` +- ``lengthSquared`` +- ``normalized`` +- ``phase`` +- ``polar`` +- ``init(length:phase:)`` + +### Scaling by real numbers +- ``multiplied(by:)`` +- ``divided(by:)`` + +### Complex-specific operations +- ``conjugate`` + +### Classification +- ``isZero`` +- ``isSubnormal`` +- ``isNormal`` +- ``isFinite`` diff --git a/Sources/ComplexModule/Documentation.docc/Magnitude.md b/Sources/ComplexModule/Documentation.docc/Magnitude.md index 9dd8331a..49ac7425 100644 --- a/Sources/ComplexModule/Documentation.docc/Magnitude.md +++ b/Sources/ComplexModule/Documentation.docc/Magnitude.md @@ -83,8 +83,8 @@ that the maximum norm lacks: ‖zw‖₂ = ‖z‖₂‖w‖₂ for any two complex numbers z and w. > Exercises: -> 1. Why isn't the maximum norm multiplicative? - (Hint: Let `z = Complex(1,1)`, and consider `z*z`.) +> 1. Find z and w that show that the maximum norm is not multiplicative. + (i.e. exhibit z and w such that ‖zw‖ ≠ ‖z‖‖w‖.) > 2. Is the 1-norm multiplicative? ### Implementation notes: From acbf4257ca3498702d25b9bfa05e3b968470dac4 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 11 Aug 2025 18:09:22 -0400 Subject: [PATCH 10/19] Remove precondition assert from Augmented.sum(large:small:) This is potentially useful to identify some bugs, but there are also algorithms (notably Kahan summation) that can be written in terms of fast2sum but would fail this check. Rework documentation to account for the change. --- Sources/RealModule/AugmentedArithmetic.swift | 43 ++++++++------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/Sources/RealModule/AugmentedArithmetic.swift b/Sources/RealModule/AugmentedArithmetic.swift index 4cd8f4b4..83118e19 100644 --- a/Sources/RealModule/AugmentedArithmetic.swift +++ b/Sources/RealModule/AugmentedArithmetic.swift @@ -9,9 +9,6 @@ // //===----------------------------------------------------------------------===// -/// Augmented arithmetic provides a family of algorithms that represent the -/// results of floating-point computations using multiple values such that -/// either the error is minimized or the result is exact. public enum Augmented { } extension Augmented { @@ -53,6 +50,10 @@ extension Augmented { /// The sum `a + b` represented as an implicit sum `head + tail`. /// + /// - Parameters: + /// - a: The summand with larger magnitude. + /// - b: The summand with smaller magnitude. + /// /// `head` is the correctly rounded value of `a + b`. `tail` is the /// error from that computation rounded to the closest representable /// value. @@ -62,15 +63,13 @@ extension Augmented { /// /// This operation is sometimes called ["fastTwoSum"]. /// - /// - Parameters: - /// - a: The summand with larger magnitude. - /// - b: The summand with smaller magnitude. - /// - /// Preconditions: - /// - /// - `large.magnitude` must not be smaller than `small.magnitude`. - /// They may be equal, or one or both may be `NaN`. - /// This precondition is only enforced in debug builds. + /// > Note: + /// > `tail` is guaranteed to be the best approximation to the error of + /// the sum only if `large.magnitude` >= `small.magnitude`. If this is + /// not the case, then `head` is the correctly rounded sum, but `tail` + /// is not guaranteed to be the exact error. If you do not know a priori + /// how the magnitudes of `a` and `b` compare, you likely want to use + /// ``sum(_:_:)`` instead. /// /// Edge Cases: /// @@ -86,29 +85,23 @@ extension Augmented { /// ["fastTwoSum"]: https://en.wikipedia.org/wiki/2Sum @_transparent public static func sum(large a: T, small b: T) -> (head: T, tail: T) { - assert(!(b.magnitude > a.magnitude)) let head = a + b let tail = a - head + b return (head, tail) } - + /// The sum `a + b` represented as an implicit sum `head + tail`. /// /// `head` is the correctly rounded value of `a + b`. `tail` is the /// error from that computation rounded to the closest representable /// value. /// - /// Unlike `Augmented.sum(large: a, small: b)`, the magnitude of the summands - /// does not matter and `a.magnitude` might as well be strictly less than - /// `b.magnitude`. However, it is recommended to only use this function over - /// `Augmented.sum(large: a, small: b)` in cases where the ordering of the - /// summands magnitude is unknown at compile time. In cases where either of - /// the summands magnitude is guaranteed to be greater than or equal the - /// magnitude of the other summand, use `Augmented.sum(large: a, small: b)` - /// over this function; as it faster to calculate. + /// Unlike ``sum(large:small:)``, the magnitude of the summands does not + /// matter. If you know statically that `a.magnitude >= b.magnitude`, you + /// should use ``sum(large:small:)``. If you do not have such a static + /// bound, you should use this function instead. /// - /// Unlike `Augmented.product(a, b)`, the rounding error of a sum can - /// never underflow. + /// Unlike ``product(_:_:)``, the rounding error of a sum never underflows. /// /// This operation is sometimes called ["twoSum"]. /// @@ -123,7 +116,7 @@ extension Augmented { /// interpreted as having any meaning (it may be `NaN` or `infinity`). /// /// Postconditions: - /// + /// /// - If `head` is normal, then `abs(tail) < head.ulp`. /// Assuming IEEE 754 default rounding, `abs(tail) <= head.ulp/2`. /// From 9c548804c8e40f4bf71e7f04225b6210fe8413a5 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 11 Aug 2025 18:11:44 -0400 Subject: [PATCH 11/19] Massage docc files to make the Documentation check happier --- Sources/ComplexModule/Complex.swift | 2 +- Sources/ComplexModule/Documentation.docc/Complex.md | 9 +++++---- .../Documentation.docc/ComplexModule.md | 6 ++++-- .../ComplexModule/Documentation.docc/Infinity.md | 4 +++- .../ComplexModule/Documentation.docc/Magnitude.md | 6 ++++-- Sources/RealModule/AugmentedArithmetic.swift | 10 ++++++---- Sources/RealModule/Documentation.docc/Augmented.md | 13 ++++++++++++- Sources/RealModule/Documentation.docc/Relaxed.md | 3 +++ 8 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Sources/ComplexModule/Complex.swift b/Sources/ComplexModule/Complex.swift index 88133e9d..ad9ed2ba 100644 --- a/Sources/ComplexModule/Complex.swift +++ b/Sources/ComplexModule/Complex.swift @@ -185,7 +185,7 @@ extension Complex { self.init(real, 0) } - /// The complex number with specified imaginary part and zero real part. + /// The complex number with zero real part and specified imaginary part. /// /// Equivalent to `Complex(0, imaginary)`. @inlinable diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index b49ae46a..ad824f7c 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -1,8 +1,9 @@ # ``Complex`` -A Complex number type that conforms to ``AlgebraicField`` (so all the normal -arithmetic operations are available) and ``ElementaryFunctions`` (so all -the usual math functions are available). +A Complex number type that conforms to `AlgebraicField` +(so all the normal arithmetic operations are available) and +`ElementaryFunctions` (so all the usual math functions are +available). A `Complex` value is represented with two `RealType` values, corresponding to the real and imaginary parts of the number. @@ -42,7 +43,7 @@ details. - ``imaginary`` - ``rawStorage`` - ``init(_:_:)`` -- ``init(_:)-(RealType)`` +- ``init(_:)-5aesj`` - ``init(imaginary:)`` ### Phase, length and magnitude diff --git a/Sources/ComplexModule/Documentation.docc/ComplexModule.md b/Sources/ComplexModule/Documentation.docc/ComplexModule.md index 8300f005..f77ecd21 100644 --- a/Sources/ComplexModule/Documentation.docc/ComplexModule.md +++ b/Sources/ComplexModule/Documentation.docc/ComplexModule.md @@ -2,7 +2,9 @@ Types and operations for working with complex numbers. -## Representation +## Overview + +### Representation The `Complex` type is generic over an associated `RealType`; complex numbers are represented as two `RealType` values, the real and imaginary parts of the @@ -28,7 +30,7 @@ Functions taking complex arguments in these other languages are not automatically converted on import, but you can safely write shims that map them into Swift types by converting pointers. -## Real-Complex arithmetic +### Real-Complex arithmetic Because the real numbers are a subset of the complex numbers, many languages support arithmetic with mixed real and complex operands. diff --git a/Sources/ComplexModule/Documentation.docc/Infinity.md b/Sources/ComplexModule/Documentation.docc/Infinity.md index 7cd45cb8..c4c1f081 100644 --- a/Sources/ComplexModule/Documentation.docc/Infinity.md +++ b/Sources/ComplexModule/Documentation.docc/Infinity.md @@ -3,6 +3,8 @@ Semantics of `Complex` zero and infinity values, and important considerations when porting code from other languages. +## Overview + Unlike C and C++'s complex types, `Complex` does not attempt to make a semantic distinction between different infinity and NaN values. Any `Complex` datum with a non-finite component is treated as the "point at infinity" on @@ -12,7 +14,7 @@ As a consequence, all values with either component infinite or NaN compare equal, and hash the same. Similarly, all zero values compare equal and hash the same. -## Rationale +### Rationale This choice has some drawbacks,¹ but also some significant advantages. In particular, complex multiplication is the most common operation performed diff --git a/Sources/ComplexModule/Documentation.docc/Magnitude.md b/Sources/ComplexModule/Documentation.docc/Magnitude.md index 49ac7425..cdd66ae0 100644 --- a/Sources/ComplexModule/Documentation.docc/Magnitude.md +++ b/Sources/ComplexModule/Documentation.docc/Magnitude.md @@ -3,6 +3,8 @@ Introduction to the concept of norm and discussion of the `Complex` type's `.magnitude` property. +## Overview + In mathematics, a *norm* is a function that gives each element of a vector space a non-negative length.¹ @@ -33,7 +35,7 @@ The three most commonly-used norms are: The `Complex` type gives special names to two of these norms; `length` for the 2-norm, and `magnitude` for the ∞-norm. -## Magnitude: +### Magnitude: The `Numeric` protocol requires us to choose a norm to call `magnitude`, but does not give guidance as to which one we should pick. The easiest choice @@ -68,7 +70,7 @@ Complex(2, 3).magnitude // 3 Complex(-1, 0.5).magnitude // 1 ``` -## Length: +### Length: The `length` property of a `Complex` value is its Euclidean norm. diff --git a/Sources/RealModule/AugmentedArithmetic.swift b/Sources/RealModule/AugmentedArithmetic.swift index 83118e19..366fdab3 100644 --- a/Sources/RealModule/AugmentedArithmetic.swift +++ b/Sources/RealModule/AugmentedArithmetic.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +/// Namespace for augmented arithmetic operations. public enum Augmented { } extension Augmented { @@ -96,10 +97,11 @@ extension Augmented { /// error from that computation rounded to the closest representable /// value. /// - /// Unlike ``sum(large:small:)``, the magnitude of the summands does not - /// matter. If you know statically that `a.magnitude >= b.magnitude`, you - /// should use ``sum(large:small:)``. If you do not have such a static - /// bound, you should use this function instead. + /// The magnitude of the summands does not change the result of this + /// operation. If you know statically that `a.magnitude >= b.magnitude`, + /// you may want to consider using ``sum(large:small:)`` to get the same + /// result somewhat more efficiently. If you do not have such a static + /// bound, you usually want to use this function instead. /// /// Unlike ``product(_:_:)``, the rounding error of a sum never underflows. /// diff --git a/Sources/RealModule/Documentation.docc/Augmented.md b/Sources/RealModule/Documentation.docc/Augmented.md index 35987015..b92214b5 100644 --- a/Sources/RealModule/Documentation.docc/Augmented.md +++ b/Sources/RealModule/Documentation.docc/Augmented.md @@ -1,5 +1,9 @@ # ``Augmented`` +A namespace for a family of algorithms that compute the results of floating- +point arithmetic using multiple values such that either the error is minimized +or the result is exact. + ## Overview Consider multiplying two Doubles. A Double has 53 significand bits, so their @@ -17,4 +21,11 @@ the low-order part of the product suddenly becomes significant: let result = 1 - c // exactly zero, but "should be" 2⁻¹⁰⁴ ``` Augmented arithmetic is a building-block that library writers can use to -handle cases like this more carefully. +handle cases like this more carefully. For the example above, one might +compute: +```swift +let (head, tail) = Augmented.product(a,b) +``` +`head` is then 1.0 and `tail` is -2⁻¹⁰⁴, so no information has been lost. +Of course, the result is now split across two Doubles instead of one, but the +information in `tail` can be carried forward into future computations. diff --git a/Sources/RealModule/Documentation.docc/Relaxed.md b/Sources/RealModule/Documentation.docc/Relaxed.md index a7a5cacb..74c5e2f8 100644 --- a/Sources/RealModule/Documentation.docc/Relaxed.md +++ b/Sources/RealModule/Documentation.docc/Relaxed.md @@ -1,5 +1,8 @@ # ``Relaxed`` +A namespace for a family of operations that "relax" the usual rules for +floating-point to allow reassociation of arithmetic and FMA formation. + ## Overview Because of rounding, and the arithmetic rules for infinity and NaN values, From c3757dc2664da239db806114073a9e8a1c197ae2 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 11 Aug 2025 19:33:27 -0400 Subject: [PATCH 12/19] Fix typo. (Thanks, Guillaume) --- Sources/RealModule/AugmentedArithmetic.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/RealModule/AugmentedArithmetic.swift b/Sources/RealModule/AugmentedArithmetic.swift index 366fdab3..94811d6f 100644 --- a/Sources/RealModule/AugmentedArithmetic.swift +++ b/Sources/RealModule/AugmentedArithmetic.swift @@ -108,7 +108,7 @@ extension Augmented { /// This operation is sometimes called ["twoSum"]. /// /// - Parameters: - /// - a: One of the summand + /// - a: One of the summands /// - b: The other summand /// /// Edge Cases: From 61a8b91b3e7962994aa2d475a3dd6a6712ca9585 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 12 Aug 2025 13:20:29 -0400 Subject: [PATCH 13/19] Some formatting cleanup around code blocks. --- Sources/ComplexModule/Documentation.docc/Magnitude.md | 7 +++++-- Sources/RealModule/Documentation.docc/Augmented.md | 6 ++++++ Sources/RealModule/Documentation.docc/Relaxed.md | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Sources/ComplexModule/Documentation.docc/Magnitude.md b/Sources/ComplexModule/Documentation.docc/Magnitude.md index cdd66ae0..f1565e34 100644 --- a/Sources/ComplexModule/Documentation.docc/Magnitude.md +++ b/Sources/ComplexModule/Documentation.docc/Magnitude.md @@ -50,15 +50,16 @@ However, there are good reasons to make a different choice: - Even when special care is used, the Euclidean and taxicab norms are not necessarily representable. Both can be infinite even for finite numbers. + ```swift let big = Double.greatestFiniteMagnitude let z = Complex(big, big) ``` + The taxicab norm of `z` would be `big + big`, which overflows; the Euclidean norm would be `sqrt(2) * big`, which also overflows. - But the maximum norm is always equal to the magnitude of either `real` - or `imaginary`, so it is necessarily representable if `z` is finite. + or `imaginary`, so it is necessarily representable. - The ∞-norm is the choice of established computational libraries, like BLAS and LAPACK. @@ -113,11 +114,13 @@ z.naiveLength // Inf // or underflow: w.naiveLength // 0 ``` + Instead, `length` is implemented using a two-step algorithm. First we compute `lengthSquared`, which is `x*x + y*y`. If this is a normal number (meaning that no overflow or underflow has occured), we can safely return its square root. Otherwise, we redo the computation with a more careful computation, which avoids spurious under- or overflow: + ```swift let z = Complex(1e20, 1e20) let w = Complex(1e-24, 1e-24) diff --git a/Sources/RealModule/Documentation.docc/Augmented.md b/Sources/RealModule/Documentation.docc/Augmented.md index b92214b5..dc60ec04 100644 --- a/Sources/RealModule/Documentation.docc/Augmented.md +++ b/Sources/RealModule/Documentation.docc/Augmented.md @@ -9,23 +9,29 @@ or the result is exact. Consider multiplying two Doubles. A Double has 53 significand bits, so their product could be up to 106 bits wide before it is rounded to a Double result. So up to 53 of those 106 bits will be "lost" in that process: + ```swift let a = 1.0 + .ulpOfOne // 1 + 2⁻⁵² let b = 1.0 - .ulpOfOne // 1 - 2⁻⁵² let c = a * b // 1 - 2⁻¹⁰⁴ before rounding, rounds to 1.0 ``` + Sometimes it is necessary to preserve some or all of those low-order bits; maybe a subsequent subtraction cancels most of the high-order bits, and so the low-order part of the product suddenly becomes significant: + ```swift let result = 1 - c // exactly zero, but "should be" 2⁻¹⁰⁴ ``` + Augmented arithmetic is a building-block that library writers can use to handle cases like this more carefully. For the example above, one might compute: + ```swift let (head, tail) = Augmented.product(a,b) ``` + `head` is then 1.0 and `tail` is -2⁻¹⁰⁴, so no information has been lost. Of course, the result is now split across two Doubles instead of one, but the information in `tail` can be carried forward into future computations. diff --git a/Sources/RealModule/Documentation.docc/Relaxed.md b/Sources/RealModule/Documentation.docc/Relaxed.md index 74c5e2f8..46623c91 100644 --- a/Sources/RealModule/Documentation.docc/Relaxed.md +++ b/Sources/RealModule/Documentation.docc/Relaxed.md @@ -7,6 +7,7 @@ floating-point to allow reassociation of arithmetic and FMA formation. Because of rounding, and the arithmetic rules for infinity and NaN values, floating-point addition and multiplication are not associative: + ```swift let ε = Double.leastNormalMagnitude let sumLeft = (-1 + 1) + ε // 0 + ε = ε @@ -16,6 +17,7 @@ let ∞ = Double.infinity let productLeft = (ε * ε) * ∞ // 0 * ∞ = .nan let productRight = ε * (ε * ∞) // ε * ∞ = ∞ ``` + For some algorithms, the distinction between these results is incidental; for some others it is critical to their correct function. Because of this, compilers cannot freely change the order of reductions, which prevents some @@ -26,6 +28,7 @@ If you know that you are in a case where the order of elements being summed or multiplied is incidental, the Relaxed operations give you a mechanism to communicate that to the compiler and unlock these optimizations. For example, consider the following two functions: + ```swift func sum(array: [Float]) -> Float { array.reduce(0, +) @@ -35,13 +38,14 @@ func relaxedSum(array: [Float]) -> Float { array.reduce(0, Relaxed.sum) } ``` + when called on an array with 1000 elements in a Release build, `relaxedSum` is about 8x faster than `sum` on Apple M2, with a similar speedup on Intel processors, without the need for any unsafe code or flags. ### multiplyAdd -In addition to `Relaxed.sum` and `Relaxed.product`, `Relaxed` provides the +In addition to `sum` and `product`, `Relaxed` provides the ``multiplyAdd(_:_:_:)`` operation, which communciates to the compiler that it is allowed to replace separate multiply and add operations with a single _fused multiply-add_ instruction if its cost model indicates that it would From 8b2fd7bbdee91b662e5752ec662f8d68b5a604a6 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 12 Aug 2025 14:52:42 -0400 Subject: [PATCH 14/19] =?UTF-8?q?Provide=20transliteration=20of=20=D0=A7?= =?UTF-8?q?=D0=B5=D0=B1=D1=8B=D1=88=D1=91=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/ComplexModule/Complex+Numeric.swift | 3 ++- Sources/ComplexModule/Documentation.docc/Complex.md | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Sources/ComplexModule/Complex+Numeric.swift b/Sources/ComplexModule/Complex+Numeric.swift index 8ec7d273..874742fe 100644 --- a/Sources/ComplexModule/Complex+Numeric.swift +++ b/Sources/ComplexModule/Complex+Numeric.swift @@ -37,7 +37,8 @@ extension Complex: Numeric { self.init(real, 0) } - /// The infinity-norm of the value (a.k.a. "maximum norm" or "Чебышёв norm"). + /// The infinity-norm of the value (a.k.a. "maximum norm" or "Чебышёв + /// [Chebyshev] norm"). /// /// Equal to `max(abs(real), abs(imaginary))`. /// diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index ad824f7c..c5ce5459 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -31,9 +31,9 @@ let im = w.imag // .nan See for more details. The ``magnitude`` property of a complex number is the infinity norm of the -value (a.k.a. “maximum norm” or “Чебышёв norm”). To get the two norm (a.k.a -"Euclidean norm"), use the ``length`` property. See for more -details. +value (a.k.a. “maximum norm” or “Чебышёв [Chebyshev] norm”). To get the two +norm (a.k.a. "Euclidean norm"), use the ``length`` property. See + for more details. ## Topics From 221387985aea3fb0d02fdd1c6f5f0aa907122e32 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 12 Aug 2025 15:04:11 -0400 Subject: [PATCH 15/19] Further review edits from Nate. --- .../Complex+AdditiveArithmetic.swift | 4 ++-- .../Complex+AlgebraicField.swift | 4 +++- Sources/ComplexModule/Complex+Codable.swift | 2 +- .../Complex+ElementaryFunctions.swift | 2 +- Sources/ComplexModule/Complex+Hashable.swift | 2 +- .../Complex+IntegerLiteral.swift | 2 +- Sources/ComplexModule/Complex+Numeric.swift | 8 +++---- .../Complex+StringConvertible.swift | 2 +- Sources/ComplexModule/Complex.swift | 21 ++++++++---------- Sources/ComplexModule/Polar.swift | 22 +++++++++---------- Sources/ComplexModule/Scale.swift | 5 ++--- 11 files changed, 34 insertions(+), 40 deletions(-) diff --git a/Sources/ComplexModule/Complex+AdditiveArithmetic.swift b/Sources/ComplexModule/Complex+AdditiveArithmetic.swift index 58f59fe1..0806fb4f 100644 --- a/Sources/ComplexModule/Complex+AdditiveArithmetic.swift +++ b/Sources/ComplexModule/Complex+AdditiveArithmetic.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019-2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -14,7 +14,7 @@ import RealModule extension Complex: AdditiveArithmetic { /// The additive identity, with real and imaginary parts both zero. /// - /// See also: `one`, `i`, `infinity` + /// See also: ``one``, ``i``, ``infinity`` @_transparent public static var zero: Complex { Complex(0, 0) diff --git a/Sources/ComplexModule/Complex+AlgebraicField.swift b/Sources/ComplexModule/Complex+AlgebraicField.swift index 42e847ad..c6f4cb85 100644 --- a/Sources/ComplexModule/Complex+AlgebraicField.swift +++ b/Sources/ComplexModule/Complex+AlgebraicField.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019-2024 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -13,6 +13,8 @@ import RealModule extension Complex: AlgebraicField { /// The multiplicative identity `1 + 0i`. + /// + /// See also: ``zero``, ``i``, ``infinity`` @_transparent public static var one: Complex { Complex(1, 0) diff --git a/Sources/ComplexModule/Complex+Codable.swift b/Sources/ComplexModule/Complex+Codable.swift index 9be3e7d9..f7f094f7 100644 --- a/Sources/ComplexModule/Complex+Codable.swift +++ b/Sources/ComplexModule/Complex+Codable.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/ComplexModule/Complex+ElementaryFunctions.swift b/Sources/ComplexModule/Complex+ElementaryFunctions.swift index 049dad05..38c8cdce 100644 --- a/Sources/ComplexModule/Complex+ElementaryFunctions.swift +++ b/Sources/ComplexModule/Complex+ElementaryFunctions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019-2020 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/ComplexModule/Complex+Hashable.swift b/Sources/ComplexModule/Complex+Hashable.swift index f2daf56a..91e43618 100644 --- a/Sources/ComplexModule/Complex+Hashable.swift +++ b/Sources/ComplexModule/Complex+Hashable.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/ComplexModule/Complex+IntegerLiteral.swift b/Sources/ComplexModule/Complex+IntegerLiteral.swift index fadb8fc6..07126fc7 100644 --- a/Sources/ComplexModule/Complex+IntegerLiteral.swift +++ b/Sources/ComplexModule/Complex+IntegerLiteral.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/ComplexModule/Complex+Numeric.swift b/Sources/ComplexModule/Complex+Numeric.swift index 874742fe..5a5d9fbe 100644 --- a/Sources/ComplexModule/Complex+Numeric.swift +++ b/Sources/ComplexModule/Complex+Numeric.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -43,16 +43,14 @@ extension Complex: Numeric { /// Equal to `max(abs(real), abs(imaginary))`. /// /// If you need to work with the Euclidean norm (a.k.a. 2-norm) instead, - /// use the `length` or `lengthSquared` properties. If you just need to - /// know "how big" a number is, use this property. + /// use the ``length`` or ``lengthSquared`` properties. If you just need + /// to know "how big" a number is, use this property. /// /// **Edge cases:** /// /// - If `z` is not finite, `z.magnitude` is infinity. /// - If `z` is zero, `z.magnitude` is zero. /// - Otherwise, `z.magnitude` is finite and non-zero. - /// - /// See also `.length` and `.lengthSquared`. @_transparent public var magnitude: RealType { guard isFinite else { return .infinity } diff --git a/Sources/ComplexModule/Complex+StringConvertible.swift b/Sources/ComplexModule/Complex+StringConvertible.swift index d1a26f07..85e7f781 100644 --- a/Sources/ComplexModule/Complex+StringConvertible.swift +++ b/Sources/ComplexModule/Complex+StringConvertible.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/ComplexModule/Complex.swift b/Sources/ComplexModule/Complex.swift index ad9ed2ba..5929a7ef 100644 --- a/Sources/ComplexModule/Complex.swift +++ b/Sources/ComplexModule/Complex.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,11 +11,8 @@ import RealModule -/// A [complex number](https://en.wikipedia.org/wiki/Complex_number). -/// -/// `Complex` is an `AlgebraicField`, so it has all the normal arithmetic -/// operators. It conforms to `ElementaryFunctions`, so it has all the usual -/// math functions. +// A [complex number](https://en.wikipedia.org/wiki/Complex_number). +// See Documentation.docc/Complex.md for more details. @frozen public struct Complex where RealType: Real { // A note on the `x` and `y` properties @@ -92,7 +89,7 @@ extension Complex { extension Complex { /// The imaginary unit. /// - /// See also `.zero`, `.one` and `.infinity`. + /// See also ``zero``, ``one`` and ``infinity``. @_transparent public static var i: Complex { Complex(0, 1) @@ -100,7 +97,7 @@ extension Complex { /// The point at infinity. /// - /// See also `.zero`, `.one` and `.i`. + /// See also ``zero``, ``one`` and ``i``. @_transparent public static var infinity: Complex { Complex(.infinity, 0) @@ -110,7 +107,7 @@ extension Complex { /// /// A complex value is finite if neither component is an infinity or nan. /// - /// See also `.isNormal`, `.isSubnormal` and `.isZero`. + /// See also ``isNormal``, ``isSubnormal`` and ``isZero``. @_transparent public var isFinite: Bool { x.isFinite && y.isFinite @@ -123,7 +120,7 @@ extension Complex { /// one of the components is normal if its exponent allows a full-precision /// representation. /// - /// See also `.isFinite`, `.isSubnormal` and `.isZero`. + /// See also ``isFinite``, ``isSubnormal`` and ``isZero``. @_transparent public var isNormal: Bool { isFinite && (x.isNormal || y.isNormal) @@ -135,7 +132,7 @@ extension Complex { /// When the result of a computation is subnormal, underflow has occurred and /// the result generally does not have full precision. /// - /// See also `.isFinite`, `.isNormal` and `.isZero`. + /// See also ``isFinite``, ``isNormal`` and ``isZero``. @_transparent public var isSubnormal: Bool { isFinite && !isNormal && !isZero @@ -146,7 +143,7 @@ extension Complex { /// A complex number is zero if *both* the real and imaginary components /// are zero. /// - /// See also `.isFinite`, `.isNormal` and `isSubnormal`. + /// See also ``isFinite``, ``isNormal`` and ``isSubnormal``. @_transparent public var isZero: Bool { x == 0 && y == 0 diff --git a/Sources/ComplexModule/Polar.swift b/Sources/ComplexModule/Polar.swift index 3a7587a8..e5dabaac 100644 --- a/Sources/ComplexModule/Polar.swift +++ b/Sources/ComplexModule/Polar.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 - 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -26,15 +26,15 @@ extension Complex { /// because the length can be as much as sqrt(2) times larger than /// either component, and thus may not be representable in the real type. /// - /// For most use cases, you can use the cheaper `.magnitude` + /// For most use cases, you can use the cheaper ``magnitude`` /// property (which computes the ∞-norm) instead, which always produces /// a representable result. See for more details. /// /// Edge cases: - /// - If a complex value is not finite, its `.length` is `infinity`. + /// - If a complex value is not finite, its `length` is `infinity`. /// - /// See also `.magnitude`, `.lengthSquared`, `.phase`, `.polar` - /// and `init(r:θ:)`. + /// See also ``lengthSquared``, ``phase``, ``polar`` + /// and ``init(length:phase:)``. @_transparent public var length: RealType { let naive = lengthSquared @@ -42,7 +42,7 @@ extension Complex { return .sqrt(naive) } - // Internal implementation detail of `length`, moving slow path off + // Internal implementation detail of ``length``, moving slow path off // of the inline function. Note that even `carefulLength` can overflow // for finite inputs, but only when the result is outside the range // of representable values. @@ -54,21 +54,19 @@ extension Complex { /// The squared length `(real*real + imaginary*imaginary)`. /// - /// This property is more efficient to compute than `length`, but is + /// This property is more efficient to compute than ``length``, but is /// highly prone to overflow or underflow; for finite values that are /// not well-scaled, `lengthSquared` is often either zero or /// infinity, even when `length` is a finite number. Use this property /// only when you are certain that this value is well-scaled. /// - /// For many cases, `.magnitude` can be used instead, which is similarly + /// For many cases, ``magnitude`` can be used instead, which is similarly /// cheap to compute and always returns a representable value. /// /// Note that because of how `lengthSquared` is used, it is a primary /// design goal that it be as fast as possible. Therefore, it does not /// normalize infinities, and may return either `.infinity` or `.nan` /// for non-finite values. - /// - /// See also ``length`` and ``magnitude``. @_transparent public var lengthSquared: RealType { x*x + y*y @@ -93,7 +91,7 @@ extension Complex { /// - If the complex value is zero or non-finite, phase is `.nan`. /// - If the complex value is non-finite, length is `.infinity`. /// - /// See also: `.length`, `.phase` and `init(r:θ:)`. + /// See also: ``length``, ``phase`` and ``init(length:phase:)``. public var polar: (length: RealType, phase: RealType) { (length, phase) } @@ -116,7 +114,7 @@ extension Complex { /// ``` /// - Otherwise, `θ` must be finite, or a precondition failure occurs. /// - /// See also `.length`, `.phase` and `.polar`. + /// See also ``length``, ``phase`` and ``polar``. @inlinable public init(length: RealType, phase: RealType) { if phase.isFinite { diff --git a/Sources/ComplexModule/Scale.swift b/Sources/ComplexModule/Scale.swift index b7ac7780..df50d577 100644 --- a/Sources/ComplexModule/Scale.swift +++ b/Sources/ComplexModule/Scale.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019-2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -33,10 +33,9 @@ extension Complex { /// `self` divided by the real value `a`. /// /// More efficient than `self / Complex(a)`. May not produce exactly the - /// same result, but will always be more accurate when they differ. + /// same result, but will always be more accurate if they differ. @inlinable @inline(__always) public func divided(by a: RealType) -> Complex { - // See implementation notes for `multiplied` above. Complex(x/a, y/a) } } From 2c19b7b8cd5ace2c15ae8edbcddd8bae0b67d56f Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 12 Aug 2025 15:13:07 -0400 Subject: [PATCH 16/19] Last few review notes on complex. --- Sources/ComplexModule/Documentation.docc/Complex.md | 9 +++------ Sources/ComplexModule/Scale.swift | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Sources/ComplexModule/Documentation.docc/Complex.md b/Sources/ComplexModule/Documentation.docc/Complex.md index c5ce5459..71984612 100644 --- a/Sources/ComplexModule/Documentation.docc/Complex.md +++ b/Sources/ComplexModule/Documentation.docc/Complex.md @@ -1,12 +1,9 @@ # ``Complex`` -A Complex number type that conforms to `AlgebraicField` -(so all the normal arithmetic operations are available) and -`ElementaryFunctions` (so all the usual math functions are -available). +A complex number type represented by its real and imaginary parts, and equipped +with the usual arithmetic operators and math functions. -A `Complex` value is represented with two `RealType` values, corresponding to -the real and imaginary parts of the number. +## Overview You can access these Cartesian components using the real and imaginary properties. diff --git a/Sources/ComplexModule/Scale.swift b/Sources/ComplexModule/Scale.swift index df50d577..37275cc3 100644 --- a/Sources/ComplexModule/Scale.swift +++ b/Sources/ComplexModule/Scale.swift @@ -22,7 +22,7 @@ // Complex! Obviously, that doesn't help anyone. extension Complex { - /// `self` multiplied by the real value `a`. + /// The result of multiplying this value by the real number `a`. /// /// Equivalent to `self * Complex(a)`, but may be computed more efficiently. @inlinable @inline(__always) @@ -30,7 +30,7 @@ extension Complex { Complex(x*a, y*a) } - /// `self` divided by the real value `a`. + /// The result of dividing this value by the real number `a`. /// /// More efficient than `self / Complex(a)`. May not produce exactly the /// same result, but will always be more accurate if they differ. From aa901641d1596eba2579118292f9ca406c348b83 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 13 Aug 2025 12:38:56 -0400 Subject: [PATCH 17/19] Further docc improvements for RealModule. This commit _also_ relaxes the constraint on Augmented algorithms from Real to FloatingPoint. It's worth calling out that fastTwoSum does not work with decimal floating-point types, so the unordered `Augemented.sum(_:_:)` now has a radix check and calls into the ordered twoSum function instead for Decimal. This makes more sense that a `BinaryFloatingPoint` constraint, as otherwise generic code written against Real or FloatingPoint would have to do the check at every call site. --- Sources/RealModule/AlgebraicField.swift | 13 +- Sources/RealModule/ApproximateEquality.swift | 10 +- Sources/RealModule/AugmentedArithmetic.swift | 36 ++++-- .../Documentation.docc/ElementaryFunctions.md | 68 ++++++++++ .../Documentation.docc/RealFunctions.md | 27 ++++ Sources/RealModule/Double+Real.swift | 2 +- Sources/RealModule/ElementaryFunctions.swift | 116 ++++++------------ Sources/RealModule/Real.swift | 4 +- Sources/RealModule/RealFunctions.swift | 73 +++++++---- Sources/RealModule/RelaxedArithmetic.swift | 10 +- 10 files changed, 222 insertions(+), 137 deletions(-) create mode 100644 Sources/RealModule/Documentation.docc/ElementaryFunctions.md create mode 100644 Sources/RealModule/Documentation.docc/RealFunctions.md diff --git a/Sources/RealModule/AlgebraicField.swift b/Sources/RealModule/AlgebraicField.swift index 230187b8..3ce5864d 100644 --- a/Sources/RealModule/AlgebraicField.swift +++ b/Sources/RealModule/AlgebraicField.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -32,12 +32,13 @@ /// Because integer multiplication does not form a group; it's commutative and /// associative, but integers do not have multiplicative inverses. /// I.e. if a is any integer other than 1 or -1, there is no integer b such -/// that a*b = 1. The existence of inverses is requried to form a field. +/// that `a*b = 1`. The existence of inverses is requried to form a field. /// -/// If a type `T` conforms to the `Real` protocol, then `T` and `Complex` +/// If a type `T` conforms to the ``Real`` protocol, then `T` and ``Complex`` /// both conform to `AlgebraicField`. /// -/// See also `Real`, `SignedNumeric`, `Numeric` and `AdditiveArithmetic`. +/// See also Swift's `SignedNumeric`, `Numeric` and `AdditiveArithmetic` +/// protocols. /// /// [field]: https://en.wikipedia.org/wiki/Field_(mathematics) public protocol AlgebraicField: SignedNumeric where Magnitude: AlgebraicField { @@ -90,10 +91,10 @@ public protocol AlgebraicField: SignedNumeric where Magnitude: AlgebraicField { /// ``` var reciprocal: Self? { get } - /// a + b, with the optimizer licensed to reassociate and form FMAs. + /// `a + b`, with the optimizer licensed to reassociate and form FMAs. static func _relaxedAdd(_ a: Self, _ b: Self) -> Self - /// a * b, with the optimizer licensed to reassociate and form FMAs. + /// `a * b`, with the optimizer licensed to reassociate and form FMAs. static func _relaxedMul(_ a: Self, _ b: Self) -> Self } diff --git a/Sources/RealModule/ApproximateEquality.swift b/Sources/RealModule/ApproximateEquality.swift index d9f8128a..8081e377 100644 --- a/Sources/RealModule/ApproximateEquality.swift +++ b/Sources/RealModule/ApproximateEquality.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2020 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2020-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -218,7 +218,7 @@ extension AdditiveArithmetic { /// norm: \.length /// ) /// ``` - /// (if we used the default norm, `.magnitude`, we would be testing if + /// (if we used the default norm, `\.magnitude`, we would be testing if /// `z` were inside a square region instead.) @inlinable public func isApproximatelyEqual( @@ -227,12 +227,6 @@ extension AdditiveArithmetic { relativeTolerance: Magnitude = 0, norm: (Self) -> Magnitude ) -> Bool - // TODO: constraint should really be weaker than FloatingPoint, - // but we need to have `isFinite` for it to work correctly with - // floating-point magnitudes in generic contexts, which is the - // most common case. The fix for this is to lift the isFinite - // requirement to Numeric in the standard library, but that's - // source-breaking, so requires an ABI rumspringa. where Magnitude: FloatingPoint { assert( absoluteTolerance >= 0 && absoluteTolerance.isFinite, diff --git a/Sources/RealModule/AugmentedArithmetic.swift b/Sources/RealModule/AugmentedArithmetic.swift index 94811d6f..bb55c277 100644 --- a/Sources/RealModule/AugmentedArithmetic.swift +++ b/Sources/RealModule/AugmentedArithmetic.swift @@ -2,14 +2,13 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2020-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // //===----------------------------------------------------------------------===// -/// Namespace for augmented arithmetic operations. public enum Augmented { } extension Augmented { @@ -40,7 +39,9 @@ extension Augmented { /// - If both `head` and `tail` are normal, then `a * b` is exactly /// equal to `head + tail` when computed as real numbers. @_transparent - public static func product(_ a: T, _ b: T) -> (head: T, tail: T) { + public static func product( + _ a: T, _ b: T + ) -> (head: T, tail: T) { let head = a*b // TODO: consider providing an FMA-less implementation for use when // targeting platforms without hardware FMA support. This works everywhere, @@ -59,11 +60,6 @@ extension Augmented { /// error from that computation rounded to the closest representable /// value. /// - /// Unlike `Augmented.product(a, b)`, the rounding error of a sum can - /// never underflow. - /// - /// This operation is sometimes called ["fastTwoSum"]. - /// /// > Note: /// > `tail` is guaranteed to be the best approximation to the error of /// the sum only if `large.magnitude` >= `small.magnitude`. If this is @@ -72,6 +68,15 @@ extension Augmented { /// how the magnitudes of `a` and `b` compare, you likely want to use /// ``sum(_:_:)`` instead. /// + /// Unlike ``product(_:_:)``, the rounding error of `sum` never underflows. + /// + /// This operation is sometimes called ["fastTwoSum"]. + /// + /// > Note: + /// > Classical fastTwoSum does not work when `radix` is 10. This function + /// will fall back on another algorithm for decimal floating-point types + /// to ensure correct results. + /// /// Edge Cases: /// /// - `head` is always the IEEE 754 sum `a + b`. @@ -85,7 +90,14 @@ extension Augmented { /// /// ["fastTwoSum"]: https://en.wikipedia.org/wiki/2Sum @_transparent - public static func sum(large a: T, small b: T) -> (head: T, tail: T) { + public static func sum( + large a: T, small b: T + ) -> (head: T, tail: T) { + // Fall back on 2Sum if radix != 2. Future implementations might use an + // cheaper algorithm specialized for decimal FP, but must deliver a + // correct result if the preconditions are satisfied. + guard T.radix == 2 else { return sum(a, b) } + // Fast2Sum: let head = a + b let tail = a - head + b return (head, tail) @@ -103,7 +115,7 @@ extension Augmented { /// result somewhat more efficiently. If you do not have such a static /// bound, you usually want to use this function instead. /// - /// Unlike ``product(_:_:)``, the rounding error of a sum never underflows. + /// Unlike ``product(_:_:)``, the rounding error of `sum` never underflows. /// /// This operation is sometimes called ["twoSum"]. /// @@ -124,7 +136,9 @@ extension Augmented { /// /// ["twoSum"]: https://en.wikipedia.org/wiki/2Sum @_transparent - public static func sum(_ a: T, _ b: T) -> (head: T, tail: T) { + public static func sum( + _ a: T, _ b: T + ) -> (head: T, tail: T) { let head = a + b let x = head - b let y = head - x diff --git a/Sources/RealModule/Documentation.docc/ElementaryFunctions.md b/Sources/RealModule/Documentation.docc/ElementaryFunctions.md new file mode 100644 index 00000000..68fb2045 --- /dev/null +++ b/Sources/RealModule/Documentation.docc/ElementaryFunctions.md @@ -0,0 +1,68 @@ +# ``ElementaryFunctions`` + + A type that has elementary functions (`sin`, `cos`, etc.) available. + +## Overview + +An ["elementary function"][elfn] is a function built up from powers, roots, +exponentials, logarithms, trigonometric functions (sin, cos, tan) and +their inverses, and the hyperbolic functions (sinh, cosh, tanh) and their +inverses. + +Conformance to this protocol means that all of these building blocks are +available as static functions on the type. + +```swift +let x: Float = 1 +let y = Float.sin(x) // 0.84147096 +``` + +`ElementaryFunctions` conformance implies `AdditiveArithmetic`, so addition +and subtraction and the `zero` property are also available. + +``RealFunctions`` refines this protocol and adds additional functions that +are primarily used with real numbers, such as ``RealFunctions/atan2(y:x:)`` +and ``RealFunctions/exp10(_:)``. + +``Real`` conforms to `RealFunctions` and `FloatingPoint`, and is the +protocol that you will use most often for generic code. + +## Topics + +There are a few families of functions defined by `ElementaryFunctions`: + +### Exponential functions +- ``exp(_:)`` +- ``expMinusOne(_:)`` + +### Logarithmetic functions +- ``log(_:)`` +- ``log(onePlus:)`` + +### Power and root functions: +- ``pow(_:_:)-9imp6`` +- ``pow(_:_:)-2qmul`` +- ``sqrt(_:)`` +- ``root(_:_:)`` + +### Trigonometric functions +- ``cos(_:)`` +- ``sin(_:)`` +- ``tan(_:)`` + +### Inverse trigonometric functions +- ``acos(_:)`` +- ``asin(_:)`` +- ``atan(_:)`` + +### Hyperbolic functions +- ``cosh(_:)`` +- ``sinh(_:)`` +- ``tanh(_:)`` + +### Inverse hyperbolic functions +- ``acosh(_:)`` +- ``asinh(_:)`` +- ``atanh(_:)`` + + [elfn]: http://en.wikipedia.org/wiki/Elementary_function diff --git a/Sources/RealModule/Documentation.docc/RealFunctions.md b/Sources/RealModule/Documentation.docc/RealFunctions.md new file mode 100644 index 00000000..0652d043 --- /dev/null +++ b/Sources/RealModule/Documentation.docc/RealFunctions.md @@ -0,0 +1,27 @@ +# ``RealFunctions`` + +A type that extends ``ElementaryFunctions`` with additional operations that +are primarily used with real numbers. + +## Topics + +### Exponential functions +- ``exp2(_:)`` +- ``exp10(_:)`` + +### Logarithmetic functions +- ``log2(_:)`` +- ``log10(_:)`` + +### Plane geometry +- ``atan2(y:x:)`` +- ``hypot(_:_:)`` + +### Gamma function +- ``gamma(_:)`` +- ``logGamma(_:)`` +- ``signGamma(_:)`` + +### Error function +- ``erf(_:)`` +- ``erfc(_:)`` diff --git a/Sources/RealModule/Double+Real.swift b/Sources/RealModule/Double+Real.swift index 4c6b3417..1a4138dd 100644 --- a/Sources/RealModule/Double+Real.swift +++ b/Sources/RealModule/Double+Real.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information diff --git a/Sources/RealModule/ElementaryFunctions.swift b/Sources/RealModule/ElementaryFunctions.swift index 0b8ccf4e..d59043b7 100644 --- a/Sources/RealModule/ElementaryFunctions.swift +++ b/Sources/RealModule/ElementaryFunctions.swift @@ -2,62 +2,19 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // //===----------------------------------------------------------------------===// -/// A type that has elementary functions (`sin`, `cos`, etc.) available. -/// -/// An ["elementary function"][elfn] is a function built up from powers, roots, -/// exponentials, logarithms, trigonometric functions (sin, cos, tan) and -/// their inverses, and the hyperbolic functions (sinh, cosh, tanh) and their -/// inverses. -/// -/// Conformance to this protocol means that all of these building blocks are -/// available as static functions on the type. -/// -/// ```swift -/// let x: Float = 1 -/// let y = Float.sin(x) // 0.84147096 -/// ``` -/// -/// There are three broad families of functions defined by -/// `ElementaryFunctions`: -/// - Exponential, trigonometric, and hyperbolic functions: -/// `exp`, `expMinusOne`, `cos`, `sin`, `tan`, `cosh`, `sinh`, and `tanh`. -/// - Logarithmic, inverse trigonometric, and inverse hyperbolic functions: -/// `log`, `log(onePlus:)`, `acos`, `asin`, `atan`, `acosh`, `asinh`, and -/// `atanh`. -/// - Power and root functions: -/// `pow`, `sqrt`, and `root`. -/// -/// `ElementaryFunctions` conformance implies `AdditiveArithmetic`, so addition -/// and subtraction and the `.zero` property are also available. -/// -/// There are two other protocols that you are more likely to want to use -/// directly: -/// -/// `RealFunctions` refines `ElementaryFunctions` and includes -/// additional functions specific to real number types. -/// -/// `Real` conforms to `RealFunctions` and `FloatingPoint`, and is the -/// protocol that you will want to use most often for generic code. -/// -/// See Also: -/// -/// - `RealFunctions` -/// - `Real` -/// -/// [elfn]: http://en.wikipedia.org/wiki/Elementary_function public protocol ElementaryFunctions: AdditiveArithmetic { /// The [exponential function][wiki] e^x whose base `e` is the base of the /// natural logarithm. /// - /// See also `expMinusOne()`, as well as `exp2()` and `exp10()` - /// defined for types conforming to `RealFunctions`. + /// For types that conform to ``RealFunctions`` see + /// ``RealFunctions/exp2(_:)`` and ``RealFunctions/exp10(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Exponential_function static func exp(_ x: Self) -> Self @@ -68,7 +25,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// catastrophic cancellation and the result will not have full accuracy. /// The `.expMinusOne(x)` function gives you a means to address this problem. /// - /// As an example, consider the expression `(x + 1)*exp(x) - 1`. When `x` + /// As an example, consider the expression `(x + 1) * .exp(x) - 1`. When `x` /// is smaller than `.ulpOfOne`, this expression evaluates to `0.0`, when it /// should actually round to `2*x`. We can get a full-accuracy result by /// using the following instead: @@ -79,8 +36,8 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// This re-written expression delivers an accurate result for all values /// of `x`, not just for small values. /// - /// See also `exp()`, as well as `exp2()` and `exp10()` defined for types - /// conforming to `RealFunctions`. + /// For types that conform to ``RealFunctions`` see + /// ``RealFunctions/exp2(_:)`` and ``RealFunctions/exp10(_:)``. static func expMinusOne(_ x: Self) -> Self /// The [hyperbolic cosine][wiki] of `x`. @@ -90,7 +47,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// 2 /// ``` /// - /// See also `sinh()`, `tanh()` and `acosh()`. + /// See also ``acosh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Hyperbolic_function static func cosh(_ x: Self) -> Self @@ -102,7 +59,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// 2 /// ``` /// - /// See also `cosh()`, `tanh()` and `asinh()`. + /// See also ``asinh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Hyperbolic_function static func sinh(_ x: Self) -> Self @@ -114,7 +71,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// cosh(x) /// ``` /// - /// See also `cosh()`, `sinh()` and `atanh()`. + /// See also ``atanh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Hyperbolic_function static func tanh(_ x: Self) -> Self @@ -123,7 +80,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, `x` may be interpreted as an angle measured in radians. /// - /// See also `sin()`, `tan()` and `acos()`. + /// See also ``acos(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Cosine static func cos(_ x: Self) -> Self @@ -133,7 +90,7 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, `x` may be interpreted as an angle measured in radians. /// - /// See also `cos()`, `tan()` and `asin()`. + /// See also ``asin(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Sine static func sin(_ x: Self) -> Self @@ -142,49 +99,54 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, `x` may be interpreted as an angle measured in radians. /// - /// See also `cos()`, `sin()` and `atan()`, as well as `atan2(y:x:)` for - /// types that conform to `RealFunctions`. + /// See also ``atan(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Tangent static func tan(_ x: Self) -> Self /// The [natural logarithm][wiki] of `x`. /// - /// See also `log(onePlus:)`, as well as `log2()` and `log10()` for types - /// that conform to `RealFunctions`. + /// For types that conform to ``RealFunctions`` see also + /// ``RealFunctions/log2(_:)`` and ``RealFunctions/log10(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Logarithm static func log(_ x: Self) -> Self /// log(1 + x), computed in such a way as to maintain accuracy for small x. /// - /// See also `log()`, as well as `log2()` and `log10()` for types - /// that conform to `RealFunctions`. + /// For types that conform to ``RealFunctions`` see also + /// ``RealFunctions/log2(_:)`` and ``RealFunctions/log10(_:)``. static func log(onePlus x: Self) -> Self /// The [inverse hyperbolic cosine][wiki] of `x`. + /// /// ``` /// cosh(acosh(x)) ≅ x /// ``` - /// See also `asinh()`, `atanh()` and `cosh()`. + /// + /// See also ``cosh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_hyperbolic_function static func acosh(_ x: Self) -> Self /// The [inverse hyperbolic sine][wiki] of `x`. + /// /// ``` /// sinh(asinh(x)) ≅ x /// ``` - /// See also `acosh()`, `atanh()` and `sinh()`. + /// + /// See also ``sinh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_hyperbolic_function static func asinh(_ x: Self) -> Self /// The [inverse hyperbolic tangent][wiki] of `x`. + /// /// ``` /// tanh(atanh(x)) ≅ x /// ``` - /// See also `acosh()`, `asinh()` and `tanh()`. + /// + /// See also ``tanh(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_hyperbolic_function static func atanh(_ x: Self) -> Self @@ -193,10 +155,12 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, the result may be interpreted as an angle measured in /// radians. + /// /// ``` /// cos(acos(x)) ≅ x /// ``` - /// See also `asin()`, `atan()` and `cos()`. + /// + /// See also ``cos(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_trigonometric_functions static func acos(_ x: Self) -> Self @@ -205,10 +169,12 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, the result may be interpreted as an angle measured in /// radians. + /// /// ``` /// sin(asin(x)) ≅ x /// ``` - /// See also `acos()`, `atan()` and `sin()`. + /// + /// See also ``sin(_:)``. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_trigonometric_functions static func asin(_ x: Self) -> Self @@ -217,11 +183,14 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// /// For real types, the result may be interpreted as an angle measured in /// radians. + /// /// ``` /// tan(atan(x)) ≅ x /// ``` - /// See also `acos()`, `asin()` and `tan()`, as well as `atan2(y:x:)` for - /// types that conform to `RealArithmetic`. + /// + /// See also ``tan(_:)``. + /// For types that conform to ``RealFunctions``, you will sometimes want + /// to use ``RealFunctions/atan2(y:x:)`` instead. /// /// [wiki]: https://en.wikipedia.org/wiki/Inverse_trigonometric_functions static func atan(_ x: Self) -> Self @@ -233,10 +202,9 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// In particular, this means that if `x` and `y` are both zero, `pow(x,y)` /// is `nan` for real types and `infinity` for complex types, rather than 1. /// - /// There is also a `pow(_:Self,_:Int)` overload, whose behavior is defined - /// in terms of repeated multiplication, and hence returns 1 for this case. - /// - /// See also `sqrt()` and `root()`. + /// There is also + /// , + /// whose behavior is defined in terms of repeated multiplication. static func pow(_ x: Self, _ y: Self) -> Self /// `x` raised to the nth power. @@ -244,19 +212,13 @@ public protocol ElementaryFunctions: AdditiveArithmetic { /// The edge-cases of this function are defined in terms of repeated /// multiplication or division, rather than exp(n log x). In particular, /// `Float.pow(0, 0)` is 1. - /// - /// See also `sqrt()` and `root()`. static func pow(_ x: Self, _ n: Int) -> Self /// The [square root][wiki] of `x`. /// - /// See also `pow()` and `root()`. - /// /// [wiki]: https://en.wikipedia.org/wiki/Square_root static func sqrt(_ x: Self) -> Self /// The nth root of `x`. - /// - /// See also `pow()` and `sqrt()`. static func root(_ x: Self, _ n: Int) -> Self } diff --git a/Sources/RealModule/Real.swift b/Sources/RealModule/Real.swift index fff6c885..3ec88300 100644 --- a/Sources/RealModule/Real.swift +++ b/Sources/RealModule/Real.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -41,7 +41,7 @@ extension Real { /// cos(x) - 1, computed in such a way as to maintain accuracy for small x. /// - /// See also `ElementaryFunctions.expMinusOne()`. + /// See also ``ElementaryFunctions.expMinusOne()``. @_transparent public static func cosMinusOne(_ x: Self) -> Self { let sinxOver2 = sin(x/2) diff --git a/Sources/RealModule/RealFunctions.swift b/Sources/RealModule/RealFunctions.swift index 31e6d165..de44752e 100644 --- a/Sources/RealModule/RealFunctions.swift +++ b/Sources/RealModule/RealFunctions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,70 +10,89 @@ //===----------------------------------------------------------------------===// public protocol RealFunctions: ElementaryFunctions { - /// `atan(y/x)`, with sign selected according to the quadrant of `(x, y)`. + /// The signed angle formed in the plane between the vector `(x,y)` and the + /// positive real axis, measured in radians. /// - /// See also `atan()`. + /// The result is in the interval `[-π, π]`. + /// + /// The argument order to `atan2` may be surprising to new programmers. + /// The convention of `y` being the first argument goes back at least to + /// Fortran IV in 1961 and is generally followed in computing with a few + /// notable exceptions (e.g. Mathematica and Excel). This convention was + /// originally chosen because of the mathematical definition of the + /// function: + /// + /// ``` + /// atan2(y,x) = atan(y/x) if x > 0 + /// ``` + /// + /// See also ``ElementaryFunctions/atan(_:)``, as well as the `phase` and + /// `polar` properties defined on the `Complex` type. static func atan2(y: Self, x: Self) -> Self - /// The error function evaluated at `x`. - /// - /// See also `erfc()`. + /// The [error function](https://en.wikipedia.org/wiki/Error_function) + /// evaluated at `x`. static func erf(_ x: Self) -> Self - /// The complimentary error function evaluated at `x`. - /// - /// See also `erf()`. + /// The complimentary [error function](https://en.wikipedia.org/wiki/Error_function) + /// evaluated at `x`. static func erfc(_ x: Self) -> Self - /// 2^x + /// 2 raised to the power x. /// - /// See also `exp()`, `expMinusOne()`, `exp10()`, `log2()` and `pow()`. + /// See also ``log2(_:)``, ``ElementaryFunctions/exp(_:)``, + /// ``ElementaryFunctions/expMinusOne(_:)`` + /// and ``ElementaryFunctions/pow(_:_:)-2qmul``. static func exp2(_ x: Self) -> Self - /// 10^x + /// 10 raised to the power x. /// - /// See also `exp()`, `expMinusOne()`, `exp2()`, `log10()` and `pow()`. + /// See also ``log10(_:)``, ``ElementaryFunctions/exp(_:)``, + /// ``ElementaryFunctions/expMinusOne(_:)`` + /// and ``ElementaryFunctions/pow(_:_:)-2qmul``. static func exp10(_ x: Self) -> Self - /// `sqrt(x*x + y*y)`, computed in a manner that avoids spurious overflow or - /// underflow. + /// The length of the vector `(x,y)`, computed in a manner that avoids + /// spurious overflow or underflow. + /// + /// See also the `length` and `polar` properties defined on the `Complex` + /// type. static func hypot(_ x: Self, _ y: Self) -> Self - /// The gamma function Γ(x). - /// - /// See also `logGamma()` and `signGamma()`. + /// The [gamma function](https://en.wikipedia.org/wiki/Gamma_function) Γ(x). static func gamma(_ x: Self) -> Self /// The base-2 logarithm of `x`. /// - /// See also `exp2()`, `log()`, `log(onePlus:)` and `log10()`. + /// See also ``exp2(_:)``, ``ElementaryFunctions/log(_:)``, + /// and ``ElementaryFunctions/log(onePlus:)``. static func log2(_ x: Self) -> Self /// The base-10 logarithm of `x`. /// - /// See also: `exp10()`, `log()`, `log(onePlus:)` and `log2()`. + /// See also ``exp10(_:)``, ``ElementaryFunctions/log(_:)``, + /// and ``ElementaryFunctions/log(onePlus:)``. static func log10(_ x: Self) -> Self #if !os(Windows) - /// The logarithm of the absolute value of the gamma function, log(|Γ(x)|). + /// The logarithm of the absolute value of the + /// [gamma function](https://en.wikipedia.org/wiki/Gamma_function), + /// log(|Γ(x)|). /// /// Not available on Windows targets. - /// - /// See also `gamma()` and `signGamma()`. static func logGamma(_ x: Self) -> Self - /// The sign of the gamma function, Γ(x). + /// The sign of the + /// [gamma function](https://en.wikipedia.org/wiki/Gamma_function), Γ(x). /// /// For `x >= 0`, `signGamma(x)` is `.plus`. For negative `x`, `signGamma(x)` /// is `.plus` when `x` is an integer, and otherwise it is `.minus` whenever /// `trunc(x)` is even, and `.plus` when `trunc(x)` is odd. /// - /// This function is used together with `logGamma`, which computes the + /// This function is used together with ``logGamma(_:)``, which computes the /// logarithm of the absolute value of Γ(x), to recover the sign information. /// /// Not available on Windows targets. - /// - /// See also `gamma()` and `logGamma()`. static func signGamma(_ x: Self) -> FloatingPointSign #endif } diff --git a/Sources/RealModule/RelaxedArithmetic.swift b/Sources/RealModule/RelaxedArithmetic.swift index e3a5865d..d0821517 100644 --- a/Sources/RealModule/RelaxedArithmetic.swift +++ b/Sources/RealModule/RelaxedArithmetic.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Numerics open source project // -// Copyright (c) 2021 Apple Inc. and the Swift Numerics project authors +// Copyright (c) 2021-2025 Apple Inc. and the Swift Numerics project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,12 +11,11 @@ import _NumericsShims -/// A namespace for "relaxed arithmetic" operations for types conforming to -/// `AlgebraicField`. public enum Relaxed { } extension Relaxed { - /// a+b with the optimizer licensed to reassociate expressions and form FMAs. + /// a+b, but grants the optimizer permission to reassociate expressions + /// and form FMAs. /// /// Floating-point addition is not an associative operation, so the Swift /// compiler does not have any flexibility in how it evaluates an expression @@ -45,7 +44,8 @@ extension Relaxed { T._relaxedAdd(a, b) } - /// a*b with the optimizer licensed to reassociate expressions and form FMAs. + /// a*b, but grants the optimizer permission to reassociate expressions + /// and form FMAs. /// /// Floating-point addition and multiplication are not associative operations, /// so the Swift compiler does not have any flexibility in how it evaluates From b3fe4357f8ffcef8b0ca49b76568ebdf4e3960f2 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 13 Aug 2025 13:50:49 -0400 Subject: [PATCH 18/19] Fix typo. --- Sources/RealModule/Real.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/RealModule/Real.swift b/Sources/RealModule/Real.swift index 3ec88300..ed6c5835 100644 --- a/Sources/RealModule/Real.swift +++ b/Sources/RealModule/Real.swift @@ -41,7 +41,7 @@ extension Real { /// cos(x) - 1, computed in such a way as to maintain accuracy for small x. /// - /// See also ``ElementaryFunctions.expMinusOne()``. + /// See also ``ElementaryFunctions/expMinusOne()``. @_transparent public static func cosMinusOne(_ x: Self) -> Self { let sinxOver2 = sin(x/2) From 1e94d2386015bde1481e4f33fb1d6f82c66e9d3d Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 13 Aug 2025 14:37:51 -0400 Subject: [PATCH 19/19] Cleanup further doc comment typos. --- Sources/RealModule/AlgebraicField.swift | 2 +- Sources/RealModule/Real.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/RealModule/AlgebraicField.swift b/Sources/RealModule/AlgebraicField.swift index 3ce5864d..d1c276bc 100644 --- a/Sources/RealModule/AlgebraicField.swift +++ b/Sources/RealModule/AlgebraicField.swift @@ -34,7 +34,7 @@ /// I.e. if a is any integer other than 1 or -1, there is no integer b such /// that `a*b = 1`. The existence of inverses is requried to form a field. /// -/// If a type `T` conforms to the ``Real`` protocol, then `T` and ``Complex`` +/// If a type `T` conforms to the ``Real`` protocol, then `T` and `Complex` /// both conform to `AlgebraicField`. /// /// See also Swift's `SignedNumeric`, `Numeric` and `AdditiveArithmetic` diff --git a/Sources/RealModule/Real.swift b/Sources/RealModule/Real.swift index ed6c5835..2f32b711 100644 --- a/Sources/RealModule/Real.swift +++ b/Sources/RealModule/Real.swift @@ -41,7 +41,7 @@ extension Real { /// cos(x) - 1, computed in such a way as to maintain accuracy for small x. /// - /// See also ``ElementaryFunctions/expMinusOne()``. + /// See also ``ElementaryFunctions/expMinusOne(_:)``. @_transparent public static func cosMinusOne(_ x: Self) -> Self { let sinxOver2 = sin(x/2)