Skip to content

Commit 58f4e72

Browse files
committed
Documentation improvements.
1 parent 8680be3 commit 58f4e72

File tree

2 files changed

+108
-17
lines changed

2 files changed

+108
-17
lines changed

Sources/IntegerUtilities/RoundingRule.swift

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,84 @@
1414
///
1515
/// [Wikipedia](https://en.wikipedia.org/wiki/Rounding#Rounding_to_integer)
1616
/// provides a good overview of different rounding rules.
17+
///
18+
/// Examples using rounding to integer to illustrate the various options:
19+
/// ```
20+
/// value | down | up | towardZero | awayFromZero |
21+
/// =======+==============+==============+==============+==============+
22+
/// 1.5 | 1 | 2 | 1 | 2 |
23+
/// -------+--------------+--------------+--------------+--------------+
24+
/// -0.5 | -1 | 0 | 0 | -1 |
25+
/// -------+--------------+--------------+--------------+--------------+
26+
/// 0.3 | 0 | 1 | 0 | 1 |
27+
/// -------+--------------+--------------+--------------+--------------+
28+
/// 2 | 2 | 2 | 2 | 2 |
29+
/// -------+--------------+--------------+--------------+--------------+
30+
///
31+
/// value | toOdd | toNearestOrAwayFromZero | toNearestOrEven |
32+
/// =======+==============+=========================+==================+
33+
/// 1.5 | 1 | 2 | 2 |
34+
/// -------+--------------+-------------------------+------------------+
35+
/// -0.5 | -1 | -1 | 0 |
36+
/// -------+--------------+-------------------------+------------------+
37+
/// 0.3 | 1 | 0 | 0 |
38+
/// -------+--------------+-------------------------+------------------+
39+
/// 2 | 2 | 2 | 2 |
40+
/// -------+--------------+-------------------------+------------------+
41+
///
42+
/// value | stochastically | requireExact |
43+
/// =======+=======================+================+
44+
/// 1.5 | 50% 1, 50% 2 | trap |
45+
/// -------+-----------------------+----------------+
46+
/// -0.5 | 50% -1, 50% 0 | trap |
47+
/// -------+-----------------------+----------------+
48+
/// 0.3 | 70% 0, 30% 1 | trap |
49+
/// -------+-----------------------+----------------+
50+
/// 2 | 2 | 2 |
51+
/// -------+-----------------------+----------------+
52+
/// ```
1753
public enum RoundingRule {
1854
/// Produces the closest representable value that is less than or equal
1955
/// to the value being rounded.
2056
///
2157
/// This is the default rounding mode for integer shifts, including the
22-
/// shift operators defined in the standard library.
58+
/// shift operators defined in the standard library.
59+
///
60+
/// Examples:
61+
/// - `(-4).divided(by: 3, rounding: .down)` is `-2`, because –2 is the
62+
/// largest integer less than –4/3 = –1.3̅
63+
/// - `5.shifted(rightBy: 1, rounding: .down)` is `2`, because 2 is the
64+
/// largest integer less than 5/2 = 2.5.
2365
case down
2466

2567
/// Produces the closest representable value that is greater than or equal
2668
/// to the value being rounded.
69+
///
70+
/// Examples:
71+
/// - `(-4).divided(by: 3, rounding: .up)` is `-1`, because –1 is the
72+
/// smallest integer greater than –4/3 = –1.3̅
73+
/// - `5.shifted(rightBy: 1, rounding: .up)` is `3`, because 3 is the
74+
/// smallest integer greater than 5/2 = 2.5.
2775
case up
2876

2977
/// Produces the closest representable value whose magnitude is less than
3078
/// or equal to that of the value being rounded.
79+
///
80+
/// Examples:
81+
/// - `(-4).divided(by: 3, rounding: .towardZero)` is `-1`, because –1
82+
/// is the closest integer to –4/3 = –1.3̅ with smaller magnitude.
83+
/// - `5.shifted(rightBy: 1, rounding: .towardZero)` is `2`, because 2
84+
/// is the closest integer to 5/2 = 2.5 with smaller magnitude.
3185
case towardZero
3286

33-
/// Produces the closest representable value whose magnitude is greater than
34-
/// or equal to that of the value being rounded.
87+
/// Produces the closest representable value whose magnitude is greater
88+
/// than or equal to that of the value being rounded.
89+
///
90+
/// Examples:
91+
/// - `(-4).divided(by: 3, rounding: .awayFromZero)` is `-2`, because –2
92+
/// is the closest integer to –4/3 = –1.3̅ with greater magnitude.
93+
/// - `5.shifted(rightBy: 1, rounding: .awayFromZero)` is `3`, because 3
94+
/// is the closest integer to 5/2 = 2.5 with greater magnitude.
3595
case awayFromZero
3696

3797
/// If the value being rounded is representable, that value is returned.
@@ -45,16 +105,37 @@ public enum RoundingRule {
45105
/// we get is the same as if we rounded directly to p₂ in the desired mode
46106
/// so long as p₂ + 1 < p₁. Other rounding modes do not have this property,
47107
/// and admit _double roundings_ when interoperating with some modes.
108+
///
109+
/// Examples:
110+
/// - `(-4).divided(by: 3, rounding: .toOdd)` is `-1`, because –4/3 = –1.3̅
111+
/// is not an exact integer, and –1 is the closest odd integer.
112+
/// - `4.shifted(rightBy: 1, rounding: .toOdd)` is `2`,
113+
/// even though 2 is even, because 4/2 is exactly 2 and no rounding occurs.
48114
case toOdd
49115

50116
/// Produces the representable value that is closest to the value being
51117
/// rounded. If two values are equally close, the one that has greater
52118
/// magnitude is returned.
119+
///
120+
/// Examples:
121+
/// - `(-4).divided(by: 3, rounding: .toNearestOrAwayFromZero)`
122+
/// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2.
123+
///
124+
/// - `5.shifted(rightBy: 1, rounding: .toNearestOrAwayFromZero)` is `3`,
125+
/// because 5/2 = 2.5 is equally close to 2 and 3, and 3 is further away
126+
/// from zero.
53127
case toNearestOrAwayFromZero
54128

55129
/// Produces the representable value that is closest to the value being
56130
/// rounded. If two values are equally close, the one whose least
57131
/// significant bit is not set is returned.
132+
///
133+
/// Examples:
134+
/// - `(-4).divided(by: 3, rounding: .toNearestOrEven)`
135+
/// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2.
136+
///
137+
/// - `5.shifted(rightBy: 1, rounding: .toNearestOrEven)` is `2`,
138+
/// because 5/2 = 2.5 is equally close to 2 and 3, and 2 is even.
58139
case toNearestOrEven
59140

60141
/// Adds a uniform random value from [0, d) to the value being rounded,
@@ -88,9 +169,19 @@ public enum RoundingRule {
88169
/// ```
89170
/// but this isn't always possible in more sophisticated scenarios,
90171
/// and in those cases this rounding rule may be useful.
172+
///
173+
/// Examples:
174+
/// - `(-4).divided(by: 3, rounding: .stochastically)`
175+
/// will be –1 with probability 2/3 and –2 with probability 1/3.
176+
/// - `5.shifted(rightBy: 1, rounding: .stochastically)`
177+
/// will be 2 with probability 1/2 and 3 with probability 1/2.
91178
case stochastically
92179

93180
/// If the value being rounded is representable, that value is returned.
94181
/// Otherwise, a precondition failure occurs.
182+
///
183+
/// Examples:
184+
/// - `(-4).divided(by: 3, rounding: .requireExact)` will trap,
185+
/// because –4/3 = –1.3̅ is not an integer.
95186
case requireExact
96187
}

Sources/IntegerUtilities/ShiftWithRounding.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ extension BinaryInteger {
2727
/// // is odd.
2828
/// 3.shifted(rightBy: 1, rounding: .toOdd)
2929
///
30-
/// // 7/2^2 = 1.75, so the result is 1 with probability 1/4, and 2
30+
/// // 7/4 = 1.75, so the result is 1 with probability 1/4, and 2
3131
/// // with probability 3/4.
3232
/// 7.shifted(rightBy: 2, rounding: .stochastically)
3333
///
34-
/// // 4/2^2 = 4/4 = 1, exactly.
34+
/// // 4/4 is exactly 1, so this does not trap.
3535
/// 4.shifted(rightBy: 2, rounding: .trap)
3636
///
37-
/// // 5/2 is 2.5, which is not exact, so this traps.
37+
/// // 5/2 is 2.5, which is not an integer, so this traps.
3838
/// 5.shifted(rightBy: 1, rounding: .requireExact)
3939
///
4040
/// When `Self(1) << count` is positive, the following are equivalent:
@@ -124,18 +124,18 @@ extension BinaryInteger {
124124
return floor + Self((round + lost) >> count)
125125
case .stochastically:
126126
// TODO: it's unfortunate that we can't specify a custom random source
127-
// for the stochastically rounding rule, but I don't see a nice way to have
128-
// that share the API with the other rounding rules, because we'd then
129-
// have to take the RNG in-out. The same problem applies to rounding
130-
// with dithering. We should consider adding a stateful rounding API
131-
// down the road to support those use cases.
127+
// for the stochastically rounding rule, but I don't see a nice way to
128+
// have that share the API with the other rounding rules, because we'd
129+
// then have to take the RNG in-out. The same problem applies to
130+
// rounding with dithering. We should consider adding a stateful
131+
// rounding API down the road to support those use cases.
132132
//
133133
// In theory, u01 should be Self.random(in: 0 ..< onesBit), but the
134134
// random(in:) method does not exist on BinaryInteger. This is
135135
// (arguably) good, though, because there's actually no reason to
136-
// generate large amounts of randomness just to implement stochastically
137-
// rounding for bigints; 32b suffices for most purposes, and 64b is
138-
// more than enough.
136+
// generate large amounts of randomness just to implement stochastic
137+
// rounding; 32b suffices for almost all purposes, and 64b is more
138+
// than enough.
139139
var g = SystemRandomNumberGenerator()
140140
let u01 = g.next()
141141
if count < 64 {
@@ -173,14 +173,14 @@ extension BinaryInteger {
173173
/// // is odd.
174174
/// 3.shifted(rightBy: 1, rounding: .toOdd)
175175
///
176-
/// // 7/2^2 = 1.75, so the result is 1 with probability 1/4, and 2
176+
/// // 7/4 = 1.75, so the result is 1 with probability 1/4, and 2
177177
/// // with probability 3/4.
178178
/// 7.shifted(rightBy: 2, rounding: .stochastically)
179179
///
180-
/// // 4/2^2 = 4/4 = 1, exactly.
180+
/// // 4/4 is exactly 1, so this does not trap.
181181
/// 4.shifted(rightBy: 2, rounding: .trap)
182182
///
183-
/// // 5/2 is 2.5, which is not exact, so this traps.
183+
/// // 5/2 is 2.5, which is not an integer, so this traps.
184184
/// 5.shifted(rightBy: 1, rounding: .requireExact)
185185
///
186186
/// When `Self(1) << count` is positive, the following are equivalent:

0 commit comments

Comments
 (0)