Skip to content

Commit aa90164

Browse files
committed
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.
1 parent 2c19b7b commit aa90164

10 files changed

+222
-137
lines changed

Sources/RealModule/AlgebraicField.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift Numerics open source project
44
//
5-
// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
5+
// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -32,12 +32,13 @@
3232
/// Because integer multiplication does not form a group; it's commutative and
3333
/// associative, but integers do not have multiplicative inverses.
3434
/// I.e. if a is any integer other than 1 or -1, there is no integer b such
35-
/// that a*b = 1. The existence of inverses is requried to form a field.
35+
/// that `a*b = 1`. The existence of inverses is requried to form a field.
3636
///
37-
/// If a type `T` conforms to the `Real` protocol, then `T` and `Complex<T>`
37+
/// If a type `T` conforms to the ``Real`` protocol, then `T` and ``Complex<T>``
3838
/// both conform to `AlgebraicField`.
3939
///
40-
/// See also `Real`, `SignedNumeric`, `Numeric` and `AdditiveArithmetic`.
40+
/// See also Swift's `SignedNumeric`, `Numeric` and `AdditiveArithmetic`
41+
/// protocols.
4142
///
4243
/// [field]: https://en.wikipedia.org/wiki/Field_(mathematics)
4344
public protocol AlgebraicField: SignedNumeric where Magnitude: AlgebraicField {
@@ -90,10 +91,10 @@ public protocol AlgebraicField: SignedNumeric where Magnitude: AlgebraicField {
9091
/// ```
9192
var reciprocal: Self? { get }
9293

93-
/// a + b, with the optimizer licensed to reassociate and form FMAs.
94+
/// `a + b`, with the optimizer licensed to reassociate and form FMAs.
9495
static func _relaxedAdd(_ a: Self, _ b: Self) -> Self
9596

96-
/// a * b, with the optimizer licensed to reassociate and form FMAs.
97+
/// `a * b`, with the optimizer licensed to reassociate and form FMAs.
9798
static func _relaxedMul(_ a: Self, _ b: Self) -> Self
9899
}
99100

Sources/RealModule/ApproximateEquality.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift Numerics open source project
44
//
5-
// Copyright (c) 2020 Apple Inc. and the Swift Numerics project authors
5+
// Copyright (c) 2020-2025 Apple Inc. and the Swift Numerics project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -218,7 +218,7 @@ extension AdditiveArithmetic {
218218
/// norm: \.length
219219
/// )
220220
/// ```
221-
/// (if we used the default norm, `.magnitude`, we would be testing if
221+
/// (if we used the default norm, `\.magnitude`, we would be testing if
222222
/// `z` were inside a square region instead.)
223223
@inlinable
224224
public func isApproximatelyEqual<Magnitude>(
@@ -227,12 +227,6 @@ extension AdditiveArithmetic {
227227
relativeTolerance: Magnitude = 0,
228228
norm: (Self) -> Magnitude
229229
) -> Bool
230-
// TODO: constraint should really be weaker than FloatingPoint,
231-
// but we need to have `isFinite` for it to work correctly with
232-
// floating-point magnitudes in generic contexts, which is the
233-
// most common case. The fix for this is to lift the isFinite
234-
// requirement to Numeric in the standard library, but that's
235-
// source-breaking, so requires an ABI rumspringa.
236230
where Magnitude: FloatingPoint {
237231
assert(
238232
absoluteTolerance >= 0 && absoluteTolerance.isFinite,

Sources/RealModule/AugmentedArithmetic.swift

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
//
33
// This source file is part of the Swift Numerics open source project
44
//
5-
// Copyright (c) 2020-2021 Apple Inc. and the Swift Numerics project authors
5+
// Copyright (c) 2020-2025 Apple Inc. and the Swift Numerics project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
/// Namespace for augmented arithmetic operations.
1312
public enum Augmented { }
1413

1514
extension Augmented {
@@ -40,7 +39,9 @@ extension Augmented {
4039
/// - If both `head` and `tail` are normal, then `a * b` is exactly
4140
/// equal to `head + tail` when computed as real numbers.
4241
@_transparent
43-
public static func product<T:Real>(_ a: T, _ b: T) -> (head: T, tail: T) {
42+
public static func product<T:FloatingPoint>(
43+
_ a: T, _ b: T
44+
) -> (head: T, tail: T) {
4445
let head = a*b
4546
// TODO: consider providing an FMA-less implementation for use when
4647
// targeting platforms without hardware FMA support. This works everywhere,
@@ -59,11 +60,6 @@ extension Augmented {
5960
/// error from that computation rounded to the closest representable
6061
/// value.
6162
///
62-
/// Unlike `Augmented.product(a, b)`, the rounding error of a sum can
63-
/// never underflow.
64-
///
65-
/// This operation is sometimes called ["fastTwoSum"].
66-
///
6763
/// > Note:
6864
/// > `tail` is guaranteed to be the best approximation to the error of
6965
/// the sum only if `large.magnitude` >= `small.magnitude`. If this is
@@ -72,6 +68,15 @@ extension Augmented {
7268
/// how the magnitudes of `a` and `b` compare, you likely want to use
7369
/// ``sum(_:_:)`` instead.
7470
///
71+
/// Unlike ``product(_:_:)``, the rounding error of `sum` never underflows.
72+
///
73+
/// This operation is sometimes called ["fastTwoSum"].
74+
///
75+
/// > Note:
76+
/// > Classical fastTwoSum does not work when `radix` is 10. This function
77+
/// will fall back on another algorithm for decimal floating-point types
78+
/// to ensure correct results.
79+
///
7580
/// Edge Cases:
7681
///
7782
/// - `head` is always the IEEE 754 sum `a + b`.
@@ -85,7 +90,14 @@ extension Augmented {
8590
///
8691
/// ["fastTwoSum"]: https://en.wikipedia.org/wiki/2Sum
8792
@_transparent
88-
public static func sum<T:Real>(large a: T, small b: T) -> (head: T, tail: T) {
93+
public static func sum<T: FloatingPoint>(
94+
large a: T, small b: T
95+
) -> (head: T, tail: T) {
96+
// Fall back on 2Sum if radix != 2. Future implementations might use an
97+
// cheaper algorithm specialized for decimal FP, but must deliver a
98+
// correct result if the preconditions are satisfied.
99+
guard T.radix == 2 else { return sum(a, b) }
100+
// Fast2Sum:
89101
let head = a + b
90102
let tail = a - head + b
91103
return (head, tail)
@@ -103,7 +115,7 @@ extension Augmented {
103115
/// result somewhat more efficiently. If you do not have such a static
104116
/// bound, you usually want to use this function instead.
105117
///
106-
/// Unlike ``product(_:_:)``, the rounding error of a sum never underflows.
118+
/// Unlike ``product(_:_:)``, the rounding error of `sum` never underflows.
107119
///
108120
/// This operation is sometimes called ["twoSum"].
109121
///
@@ -124,7 +136,9 @@ extension Augmented {
124136
///
125137
/// ["twoSum"]: https://en.wikipedia.org/wiki/2Sum
126138
@_transparent
127-
public static func sum<T: Real>(_ a: T, _ b: T) -> (head: T, tail: T) {
139+
public static func sum<T: FloatingPoint>(
140+
_ a: T, _ b: T
141+
) -> (head: T, tail: T) {
128142
let head = a + b
129143
let x = head - b
130144
let y = head - x
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# ``ElementaryFunctions``
2+
3+
A type that has elementary functions (`sin`, `cos`, etc.) available.
4+
5+
## Overview
6+
7+
An ["elementary function"][elfn] is a function built up from powers, roots,
8+
exponentials, logarithms, trigonometric functions (sin, cos, tan) and
9+
their inverses, and the hyperbolic functions (sinh, cosh, tanh) and their
10+
inverses.
11+
12+
Conformance to this protocol means that all of these building blocks are
13+
available as static functions on the type.
14+
15+
```swift
16+
let x: Float = 1
17+
let y = Float.sin(x) // 0.84147096
18+
```
19+
20+
`ElementaryFunctions` conformance implies `AdditiveArithmetic`, so addition
21+
and subtraction and the `zero` property are also available.
22+
23+
``RealFunctions`` refines this protocol and adds additional functions that
24+
are primarily used with real numbers, such as ``RealFunctions/atan2(y:x:)``
25+
and ``RealFunctions/exp10(_:)``.
26+
27+
``Real`` conforms to `RealFunctions` and `FloatingPoint`, and is the
28+
protocol that you will use most often for generic code.
29+
30+
## Topics
31+
32+
There are a few families of functions defined by `ElementaryFunctions`:
33+
34+
### Exponential functions
35+
- ``exp(_:)``
36+
- ``expMinusOne(_:)``
37+
38+
### Logarithmetic functions
39+
- ``log(_:)``
40+
- ``log(onePlus:)``
41+
42+
### Power and root functions:
43+
- ``pow(_:_:)-9imp6``
44+
- ``pow(_:_:)-2qmul``
45+
- ``sqrt(_:)``
46+
- ``root(_:_:)``
47+
48+
### Trigonometric functions
49+
- ``cos(_:)``
50+
- ``sin(_:)``
51+
- ``tan(_:)``
52+
53+
### Inverse trigonometric functions
54+
- ``acos(_:)``
55+
- ``asin(_:)``
56+
- ``atan(_:)``
57+
58+
### Hyperbolic functions
59+
- ``cosh(_:)``
60+
- ``sinh(_:)``
61+
- ``tanh(_:)``
62+
63+
### Inverse hyperbolic functions
64+
- ``acosh(_:)``
65+
- ``asinh(_:)``
66+
- ``atanh(_:)``
67+
68+
[elfn]: http://en.wikipedia.org/wiki/Elementary_function
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# ``RealFunctions``
2+
3+
A type that extends ``ElementaryFunctions`` with additional operations that
4+
are primarily used with real numbers.
5+
6+
## Topics
7+
8+
### Exponential functions
9+
- ``exp2(_:)``
10+
- ``exp10(_:)``
11+
12+
### Logarithmetic functions
13+
- ``log2(_:)``
14+
- ``log10(_:)``
15+
16+
### Plane geometry
17+
- ``atan2(y:x:)``
18+
- ``hypot(_:_:)``
19+
20+
### Gamma function
21+
- ``gamma(_:)``
22+
- ``logGamma(_:)``
23+
- ``signGamma(_:)``
24+
25+
### Error function
26+
- ``erf(_:)``
27+
- ``erfc(_:)``

Sources/RealModule/Double+Real.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift Numerics open source project
44
//
5-
// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
5+
// Copyright (c) 2019-2025 Apple Inc. and the Swift Numerics project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information

0 commit comments

Comments
 (0)