|
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