Skip to content

Commit 53efe07

Browse files
committed
Adopt new rounding rules for midpoint
Also corrects a typo and makes the deprecated toNearestOrAwayFromZero rule public for migration purposes, and removes the BinaryInteger.midpoint function in favor of the FixedWidthInteger overload. I'm open to reinstating the BI implementation in the future, but let's start with just FWI.
1 parent 64c0625 commit 53efe07

File tree

3 files changed

+12
-53
lines changed

3 files changed

+12
-53
lines changed

Sources/IntegerUtilities/Midpoint.swift

+7-51
Original file line numberDiff line numberDiff line change
@@ -9,55 +9,6 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
/// The average of `a` and `b`, rounded to an integer according to `rule`.
13-
///
14-
/// Unlike commonly seen expressions such as `(a+b)/2` or `(a+b) >> 1` or
15-
/// `a + (b-a)/2` (all of which may overflow for fixed-width integers),
16-
/// this function never overflows, and the result is guaranteed to be
17-
/// representable in the result type.
18-
///
19-
/// The default rounding rule is `.down`, which matches the behavior of
20-
/// `(a + b) >> 1` when that expression does not overflow. Rounding
21-
/// `.towardZero` matches the behavior of `(a + b)/2` when that expression
22-
/// does not overflow. All other rounding modes are supported.
23-
///
24-
/// Rounding `.down` is generally most efficient; if you do not have a
25-
/// reason to chose a specific other rounding rule, you should use the
26-
/// default.
27-
@inlinable
28-
public func midpoint<T: BinaryInteger>(
29-
_ a: T,
30-
_ b: T,
31-
rounding rule: RoundingRule = .down
32-
) -> T {
33-
// Isolate bits in a + b with weight 2, and those with weight 1.
34-
let twos = a & b
35-
let ones = a ^ b
36-
let floor = twos + ones >> 1
37-
let frac = ones & 1
38-
switch rule {
39-
case .down:
40-
return floor
41-
case .up:
42-
return floor + frac
43-
case .towardZero:
44-
return floor + (floor < 0 ? frac : 0)
45-
case .toNearestOrAwayFromZero:
46-
fallthrough
47-
case .awayFromZero:
48-
return floor + (floor >= 0 ? frac : 0)
49-
case .toNearestOrEven:
50-
return floor + (floor & frac)
51-
case .toOdd:
52-
return floor + (~floor & frac)
53-
case .stochastically:
54-
return floor + (Bool.random() ? frac : 0)
55-
case .requireExact:
56-
precondition(frac == 0)
57-
return floor
58-
}
59-
}
60-
6112
/// The average of `a` and `b`, rounded to an integer according to `rule`.
6213
///
6314
/// Unlike commonly seen expressions such as `(a+b)/2` or `(a+b) >> 1` or
@@ -84,13 +35,19 @@ public func midpoint<T: FixedWidthInteger>(
8435
let floor = twos &+ ones >> 1
8536
let frac = ones & 1
8637
switch rule {
38+
case .toNearestOrDown:
39+
fallthrough
8740
case .down:
8841
return floor
42+
case .toNearestOrUp:
43+
fallthrough
8944
case .up:
9045
return floor &+ frac
46+
case .toNearestOrZero:
47+
fallthrough
9148
case .towardZero:
9249
return floor &+ (floor < 0 ? frac : 0)
93-
case .toNearestOrAwayFromZero:
50+
case .toNearestOrAway:
9451
fallthrough
9552
case .awayFromZero:
9653
return floor &+ (floor >= 0 ? frac : 0)
@@ -105,4 +62,3 @@ public func midpoint<T: FixedWidthInteger>(
10562
return floor
10663
}
10764
}
108-

Sources/IntegerUtilities/RoundingRule.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,5 +256,5 @@ extension RoundingRule {
256256
/// > Deprecated: Use `.toNearestOrAway` instead.
257257
@inlinable
258258
@available(*, deprecated, renamed: "toNearestOrAway")
259-
static var toNearestOrAwayFromZero: Self { .toNearestOrAway }
259+
public static var toNearestOrAwayFromZero: Self { .toNearestOrAway }
260260
}

Tests/IntegerUtilitiesTests/MidpointTests.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ final class IntegerUtilitiesMidpointTests: XCTestCase {
2020
.up,
2121
.towardZero,
2222
.awayFromZero,
23+
.toNearestOrDown,
24+
.toNearestOrUp,
25+
.toNearestOrZero,
26+
.toNearestOrAway,
2327
.toNearestOrEven,
24-
.toNearestOrAwayFromZero,
2528
.toOdd
2629
] {
2730
for a in -128 ... 127 {

0 commit comments

Comments
 (0)