Skip to content

Commit 1e72483

Browse files
committed
Add twoSum to augmented arithmetic
1 parent 1b3e3f1 commit 1e72483

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

Sources/RealModule/AugmentedArithmetic.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ extension Augmented {
6464
/// never underflow. However, it may not be exactly representable when
6565
/// `a` and `b` differ widely in magnitude.
6666
///
67-
/// This operation is sometimes called "fastTwoSum".
67+
/// This operation is sometimes called ["fastTwoSum"].
6868
///
6969
/// - Parameters:
7070
/// - a: The summand with larger magnitude.
@@ -86,11 +86,60 @@ extension Augmented {
8686
/// -
8787
/// - If `head` is normal, then `abs(tail) < head.ulp`.
8888
/// Assuming IEEE 754 default rounding, `abs(tail) <= head.ulp/2`.
89+
///
90+
/// ["fastTwoSum"]: https://en.wikipedia.org/wiki/2Sum
8991
@_transparent
9092
public static func sum<T:Real>(large a: T, small b: T) -> (head: T, tail: T) {
9193
assert(!(b.magnitude > a.magnitude))
9294
let head = a + b
9395
let tail = a - head + b
9496
return (head, tail)
9597
}
98+
99+
/// The sum `a + b` represented as an implicit sum `head + tail`.
100+
///
101+
/// `head` is the correctly rounded value of `a + b`. `tail` is the
102+
/// error from that computation rounded to the closest representable
103+
/// value.
104+
///
105+
/// Unlike `Augmented.sum(large:, small:)`, the magnitude of the summands
106+
/// does not matter. `a.magnitude` might as well be smaller than
107+
/// `b.magnitude` – and vice versa. However, it is recommended to only use
108+
/// this function over `Augmented.sum(large:, small:)` in cases where the
109+
/// ordering of the summands magnitude is unknown at compile time. In cases
110+
/// where either of the summands magnitude is known to be greater than or
111+
/// equal the magnitude of the other summand, use
112+
/// `Augmented.sum(large:, small:)` over this function; as it faster to
113+
/// calculate.
114+
///
115+
/// Unlike `Augmented.product(a, b)`, the rounding error of a sum can
116+
/// never underflow. However, it may not be exactly representable when
117+
/// `a` and `b` differ widely in magnitude.
118+
///
119+
/// This operation is sometimes called ["twoSum"].
120+
///
121+
/// - Parameters:
122+
/// - a: One of the summand
123+
/// - b: The other summand
124+
///
125+
/// Edge Cases:
126+
/// -
127+
/// - `head` is always the IEEE 754 sum `a + b`.
128+
/// - If `head` is not finite, `tail` is unspecified and should not be
129+
/// interpreted as having any meaning (it may be `NaN` or `infinity`).
130+
///
131+
/// Postconditions:
132+
/// -
133+
/// - If `head` is normal, then `abs(tail) < head.ulp`.
134+
/// Assuming IEEE 754 default rounding, `abs(tail) <= head.ulp/2`.
135+
///
136+
/// ["twoSum"]: https://en.wikipedia.org/wiki/2Sum
137+
@_transparent
138+
public static func sum<T:Real>(_ a: T, _ b: T) -> (head: T, tail: T) {
139+
let head = a + b
140+
let x = head - a
141+
let y = head - x
142+
let tail = (a - x) + (b - y)
143+
return (head, tail)
144+
}
96145
}

0 commit comments

Comments
 (0)