|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift Numerics open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2021 Apple Inc. and the Swift Numerics project authors |
| 5 | +// Copyright (c) 2021-2024 Apple Inc. and the Swift Numerics project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
9 | 9 | //
|
10 | 10 | //===----------------------------------------------------------------------===//
|
11 | 11 |
|
| 12 | +// TODO: it's unfortunate that we can't specify a custom random source |
| 13 | +// for the stochastic rounding rule, but I don't see a nice way to have |
| 14 | +// that share the API with the other rounding rules, because we'd then |
| 15 | +// have to take either the rule in-out or have an additional RNG/state |
| 16 | +// parameter. The same problem applies to rounding with dithering and |
| 17 | +// any other stateful rounding method. We should consider adding a |
| 18 | +// stateful rounding API down the road to support those use cases. |
| 19 | + |
12 | 20 | /// A rule that defines how to select one of the two representable results
|
13 | 21 | /// closest to a given value.
|
14 | 22 | ///
|
|
17 | 25 | ///
|
18 | 26 | /// Examples using rounding to integer to illustrate the various options:
|
19 | 27 | /// ```
|
| 28 | +/// Directed rounding rules |
| 29 | +/// |
20 | 30 | /// value | down | up | towardZero | awayFromZero |
|
21 | 31 | /// =======+==============+==============+==============+==============+
|
22 |
| -/// 1.5 | 1 | 2 | 1 | 2 | |
| 32 | +/// -1.5 | -2 | -1 | -1 | -2 | |
23 | 33 | /// -------+--------------+--------------+--------------+--------------+
|
24 | 34 | /// -0.5 | -1 | 0 | 0 | -1 |
|
25 | 35 | /// -------+--------------+--------------+--------------+--------------+
|
26 |
| -/// 0.3 | 0 | 1 | 0 | 1 | |
| 36 | +/// 0.5 | 0 | 1 | 0 | 1 | |
| 37 | +/// -------+--------------+--------------+--------------+--------------+ |
| 38 | +/// 0.7 | 0 | 1 | 0 | 1 | |
27 | 39 | /// -------+--------------+--------------+--------------+--------------+
|
28 |
| -/// 2 | 2 | 2 | 2 | 2 | |
| 40 | +/// 1.2 | 1 | 2 | 1 | 2 | |
29 | 41 | /// -------+--------------+--------------+--------------+--------------+
|
| 42 | +/// 2.0 | 2 | 2 | 2 | 2 | |
| 43 | +/// -------+--------------+--------------+--------------+--------------+ |
| 44 | +/// |
| 45 | +/// toNearestOr... rounding rules |
30 | 46 | ///
|
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 |
| -/// -------+--------------+-------------------------+------------------+ |
| 47 | +/// value | orDown | orUp | orZero | orAway | orEven | |
| 48 | +/// =======+==========+==========+==========+==========+==========+ |
| 49 | +/// -1.5 | -2 | -1 | -1 | -2 | -2 | |
| 50 | +/// -------+----------+----------+----------+----------+----------+ |
| 51 | +/// -0.5 | -1 | 0 | 0 | -1 | 0 | |
| 52 | +/// -------+----------+----------+----------+----------+----------+ |
| 53 | +/// 0.5 | 0 | 1 | 0 | 1 | 0 | |
| 54 | +/// -------+----------+----------+----------+----------+----------+ |
| 55 | +/// 0.7 | 1 | 1 | 1 | 1 | 1 | |
| 56 | +/// -------+----------+----------+----------+----------+----------+ |
| 57 | +/// 1.2 | 1 | 1 | 1 | 1 | 1 | |
| 58 | +/// -------+----------+----------+----------+----------+----------+ |
| 59 | +/// 2.0 | 2 | 2 | 2 | 2 | 2 | |
| 60 | +/// -------+----------+----------+----------+----------+----------+ |
41 | 61 | ///
|
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 |
| -/// -------+-----------------------+----------------+ |
| 62 | +/// Specialized rounding rules |
| 63 | +/// |
| 64 | +/// value | toOdd | stochastically | requireExact | |
| 65 | +/// =======+==============+=======================+================+ |
| 66 | +/// -1.5 | -1 | 50% -2, 50% -1 | trap | |
| 67 | +/// -------+--------------+-----------------------+----------------+ |
| 68 | +/// -0.5 | -1 | 50% -1, 50% 0 | trap | |
| 69 | +/// -------+--------------+-----------------------+----------------+ |
| 70 | +/// 0.5 | 1 | 50% 0, 50% 1 | trap | |
| 71 | +/// -------+--------------+-----------------------+----------------+ |
| 72 | +/// 0.7 | 1 | 30% 0, 70% 1 | trap | |
| 73 | +/// -------+--------------+-----------------------+----------------+ |
| 74 | +/// 1.2 | 1 | 80% 1, 20% 2 | trap | |
| 75 | +/// -------+--------------+-----------------------+----------------+ |
| 76 | +/// 2.0 | 2 | 2 | 2 | |
| 77 | +/// -------+--------------+-----------------------+----------------+ |
52 | 78 | /// ```
|
53 | 79 | public enum RoundingRule {
|
54 | 80 | /// Produces the closest representable value that is less than or equal
|
@@ -113,18 +139,54 @@ public enum RoundingRule {
|
113 | 139 | /// even though 2 is even, because 4/2 is exactly 2 and no rounding occurs.
|
114 | 140 | case toOdd
|
115 | 141 |
|
| 142 | + /// Produces the representable value that is closest to the value being |
| 143 | + /// rounded. If two values are equally close, the one that is less than |
| 144 | + /// the value being rounded is chosen. |
| 145 | + /// |
| 146 | + /// Examples: |
| 147 | + /// - `(-4).divided(by: 3, rounding: .toNearestOrDown)` |
| 148 | + /// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2. |
| 149 | + /// |
| 150 | + /// - `5.shifted(rightBy: 1, rounding: .toNearestOrDown)` is `2`, |
| 151 | + /// because 5/2 = 2.5 is equally close to 2 and 3, and 2 is less. |
| 152 | + case toNearestOrDown |
| 153 | + |
| 154 | + /// Produces the representable value that is closest to the value being |
| 155 | + /// rounded. If two values are equally close, the one that is greater than |
| 156 | + /// the value being rounded is chosen. |
| 157 | + /// |
| 158 | + /// Examples: |
| 159 | + /// - `(-4).divided(by: 3, rounding: .toNearestOrUp)` |
| 160 | + /// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2. |
| 161 | + /// |
| 162 | + /// - `5.shifted(rightBy: 1, rounding: .toNearestOrUp)` is `3`, |
| 163 | + /// because 5/2 = 2.5 is equally close to 2 and 3, and 3 is greater. |
| 164 | + case toNearestOrUp |
| 165 | + |
| 166 | + /// Produces the representable value that is closest to the value being |
| 167 | + /// rounded. If two values are equally close, the one that has smaller |
| 168 | + /// magnitude is returned. |
| 169 | + /// |
| 170 | + /// Examples: |
| 171 | + /// - `(-4).divided(by: 3, rounding: .toNearestOrZero)` |
| 172 | + /// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2. |
| 173 | + /// |
| 174 | + /// - `5.shifted(rightBy: 1, rounding: .toNearestOrZero)` is `3`, |
| 175 | + /// because 5/2 = 2.5 is equally close to 2 and 3, and 2 is closer to zero. |
| 176 | + case toNearestOrZero |
| 177 | + |
116 | 178 | /// Produces the representable value that is closest to the value being
|
117 | 179 | /// rounded. If two values are equally close, the one that has greater
|
118 | 180 | /// magnitude is returned.
|
119 | 181 | ///
|
120 | 182 | /// Examples:
|
121 |
| - /// - `(-4).divided(by: 3, rounding: .toNearestOrAwayFromZero)` |
| 183 | + /// - `(-4).divided(by: 3, rounding: .toNearestOrAway)` |
122 | 184 | /// is `-1`, because –4/3 = –1.3̅ is closer to –1 than it is to –2.
|
123 | 185 | ///
|
124 |
| - /// - `5.shifted(rightBy: 1, rounding: .toNearestOrAwayFromZero)` is `3`, |
| 186 | + /// - `5.shifted(rightBy: 1, rounding: .toNearestOrAway)` is `3`, |
125 | 187 | /// because 5/2 = 2.5 is equally close to 2 and 3, and 3 is further away
|
126 | 188 | /// from zero.
|
127 |
| - case toNearestOrAwayFromZero |
| 189 | + case toNearestOrAway |
128 | 190 |
|
129 | 191 | /// Produces the representable value that is closest to the value being
|
130 | 192 | /// rounded. If two values are equally close, the one whose least
|
@@ -185,3 +247,14 @@ public enum RoundingRule {
|
185 | 247 | /// because –4/3 = –1.3̅ is not an integer.
|
186 | 248 | case requireExact
|
187 | 249 | }
|
| 250 | + |
| 251 | +extension RoundingRule { |
| 252 | + /// Produces the representable value that is closest to the value being |
| 253 | + /// rounded. If two values are equally close, the one that has greater |
| 254 | + /// magnitude is returned. |
| 255 | + /// |
| 256 | + /// > Deprecated: Use `.toNearestOrAway` instead. |
| 257 | + @inlinable |
| 258 | + @available(*, deprecated, renamed: "toNearestOrAway") |
| 259 | + static var toNearestOrAwayFromZero: Self { .toNearestOrAway } |
| 260 | +} |
0 commit comments