devela/num/int/wrapper/
impl_div.rs

1// devela::num::int::wrapper::impl_div
2//
3//! Implements division-related methods for [`Int`].
4//
5// TOC
6// - signed|unsigned:
7//   - div_rem
8//   - div_ceil
9//   - div_floor
10//   - div_ties_away
11//   - div_ties_towards
12//   - div_ties_even
13//   - div_ties_odd
14
15use super::super::shared_docs::*;
16use crate::{iif, paste, Int};
17
18/// Implements division-related methods for [`Int`].
19///
20/// # Args
21/// $t:   the input/output type
22/// $cap: the capability feature that enables the given implementation. E.g "_int_i8"
23///
24/// $d:   the doclink suffix for the method name
25macro_rules! impl_div {
26    () => {
27        impl_div![signed
28            i8    :"_int_i8":"",
29            i16   :"_int_i16":"-1",
30            i32   :"_int_i32":"-2",
31            i64   :"_int_i64":"-3",
32            i128  :"_int_i128":"-4",
33            isize :"_int_isize":"-5"
34        ];
35        impl_div![unsigned
36            u8    :"_int_u8"    :"-6",
37            u16   :"_int_u16"   :"-7",
38            u32   :"_int_u32"   :"-8",
39            u64   :"_int_u64"   :"-9",
40            u128  :"_int_u128"  :"-10",
41            usize :"_int_usize" :"-11"
42        ];
43    };
44    (signed $( $t:ty : $cap:literal : $d:literal ),+) => {
45        $( impl_div![@signed $t:$cap:$d]; )+
46    };
47    (unsigned $( $t:ty : $cap:literal : $d:literal ),+) => {
48        $( impl_div![@unsigned $t:$cap:$d]; )+
49    };
50    (
51    // implements signed ops
52    @signed $t:ty : $cap:literal : $d:literal) => { paste! {
53        #[doc = crate::doc_availability!(feature = $cap)]
54        ///
55        #[doc = "# Integer division related methods for `" $t "`\n\n"]
56        #[doc = "- [div_rem](#method.div_rem" $d ")"]
57        #[doc = "- [div_ceil](#method.div_ceil" $d ")"]
58        #[doc = "- [div_floor](#method.div_floor" $d ")"]
59        #[doc = "- [div_ties_away](#method.div_ties_away" $d ")"]
60        #[doc = "- [div_ties_towards](#method.div_ties_towards" $d ")"]
61        #[doc = "- [div_ties_even](#method.div_ties_even" $d ")"]
62        #[doc = "- [div_ties_odd](#method.div_ties_odd" $d ")"]
63        ///
64        #[cfg(feature = $cap )]
65        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
66        impl Int<$t> {
67            /// Returns the truncated quotient and the remainder.
68            #[must_use]
69            pub const fn div_rem(self, b: $t) -> [Int<$t>; 2] {
70                let a = self.0; [Int(a / b), Int(a % b)]
71            }
72
73            /// Returns the quotient, rounding the result towards positive infinity.
74            #[doc = NOTATION_DIV_CEIL!()]
75            ///
76            /// # Formulation
77            #[doc = FORMULA_DIV_CEIL!()]
78            /// # Examples
79            /// ```
80            /// # use devela::Int;
81            #[doc = "assert_eq![Int(7_" $t ").div_ceil(3), Int(3)]; // == 2.33…"]
82            #[doc = "assert_eq![Int(7_" $t ").div_ceil(-3), Int(-2)];"]
83            #[doc = "assert_eq![Int(-7_" $t ").div_ceil(3), Int(-2)];"]
84            #[doc = "assert_eq![Int(-7_" $t ").div_ceil(-3), Int(3)];"]
85            ///
86            #[doc = "assert_eq![Int(7_" $t ").div_ceil(5), Int(2)]; // == 1.4"]
87            #[doc = "assert_eq![Int(6_" $t ").div_ceil(4), Int(2)]; // == 1.5"]
88            #[doc = "assert_eq![Int(8_" $t ").div_ceil(5), Int(2)]; // == 1.6"]
89            #[doc = "assert_eq![Int(5_" $t ").div_ceil(2), Int(3)]; // == 2.5"]
90            #[doc = "assert_eq![Int(-7_" $t ").div_ceil(5), Int(-1)]; // == -1.4"]
91            #[doc = "assert_eq![Int(-6_" $t ").div_ceil(4), Int(-1)]; // == -1.5"]
92            #[doc = "assert_eq![Int(-8_" $t ").div_ceil(5), Int(-1)]; // == -1.6"]
93            #[doc = "assert_eq![Int(-5_" $t ").div_ceil(2), Int(-2)]; // == -2.5"]
94            /// ```
95            // unstable rust implementation for signed integers:
96            // WAIT: [int_roundings](https://github.com/rust-lang/rust/issues/88581)
97            #[must_use]
98            pub const fn div_ceil(self, b: $t) -> Int<$t> {
99                let a = self.0; let (d, r) = (a / b, a % b);
100                iif![(r > 0 && b > 0) || (r < 0 && b < 0); Int(d + 1); Int(d)]
101            }
102            // alternative implementation:
103            // pub const fn div_ceil(self, b: $t) -> $t {
104            //     let a = self.0; iif![a > 0 && b > 0; ((a - 1) / b) + 1 ; a / b ]
105            // }
106
107            /// Returns the quotient, rounding the result towards negative infinity.
108            #[doc = NOTATION_DIV_FLOOR!()]
109            /// # Examples
110            /// ```
111            /// # use devela::Int;
112            #[doc = "assert_eq![Int(7_" $t ").div_floor(3), Int(2)]; // == 2.33…"]
113            #[doc = "assert_eq![Int(7_" $t ").div_floor(-3), Int(-3)];"]
114            #[doc = "assert_eq![Int(-7_" $t ").div_floor(3), Int(-3)];"]
115            #[doc = "assert_eq![Int(-7_" $t ").div_floor(-3), Int(2)];"]
116            ///
117            #[doc = "assert_eq![Int(7_" $t ").div_floor(5), Int(1)]; // == 1.4"]
118            #[doc = "assert_eq![Int(6_" $t ").div_floor(4), Int(1)]; // == 1.5"]
119            #[doc = "assert_eq![Int(8_" $t ").div_floor(5), Int(1)]; // == 1.6"]
120            #[doc = "assert_eq![Int(5_" $t ").div_floor(2), Int(2)]; // == 2.5"]
121            #[doc = "assert_eq![Int(-7_" $t ").div_floor(5), Int(-2)]; // == -1.4"]
122            #[doc = "assert_eq![Int(-6_" $t ").div_floor(4), Int(-2)]; // == -1.5"]
123            #[doc = "assert_eq![Int(-8_" $t ").div_floor(5), Int(-2)]; // == -1.6"]
124            #[doc = "assert_eq![Int(-5_" $t ").div_floor(2), Int(-3)]; // == -2.5"]
125            /// ```
126            // unstable rust implementation for signed integers:
127            // WAIT: [int_roundings](https://github.com/rust-lang/rust/issues/88581)
128            #[must_use]
129            pub const fn div_floor(self, b: $t) -> Int<$t> {
130                let a = self.0; let (d, r) = (a / b, a % b);
131                iif![(r > 0 && b < 0) || (r < 0 && b > 0); Int(d - 1); Int(d)]
132            }
133
134            /// Returns the quotient, rounding ties away from zero.
135            /// # Examples
136            /// ```
137            /// # use devela::Int;
138            #[doc = "assert_eq![Int(7_" $t ").div_ties_away(3), Int(2)]; // == 2.33…"]
139            #[doc = "assert_eq![Int(7_" $t ").div_ties_away(-3), Int(-2)];"]
140            #[doc = "assert_eq![Int(-7_" $t ").div_ties_away(3), Int(-2)];"]
141            #[doc = "assert_eq![Int(-7_" $t ").div_ties_away(-3), Int(2)];"]
142            ///
143            #[doc = "assert_eq![Int(7_" $t ").div_ties_away(5), Int(1)]; // == 1.4"]
144            #[doc = "assert_eq![Int(6_" $t ").div_ties_away(4), Int(2)]; // == 1.5"]
145            #[doc = "assert_eq![Int(8_" $t ").div_ties_away(5), Int(2)]; // == 1.6"]
146            #[doc = "assert_eq![Int(5_" $t ").div_ties_away(2), Int(3)]; // == 2.5"]
147            #[doc = "assert_eq![Int(-7_" $t ").div_ties_away(5), Int(-1)]; // == -1.4"]
148            #[doc = "assert_eq![Int(-6_" $t ").div_ties_away(4), Int(-2)]; // == -1.5"]
149            #[doc = "assert_eq![Int(-8_" $t ").div_ties_away(5), Int(-2)]; // == -1.6"]
150            #[doc = "assert_eq![Int(-5_" $t ").div_ties_away(2), Int(-3)]; // == -2.5"]
151            /// ```
152            #[must_use]
153            pub const fn div_ties_away(self, b: $t) -> Int<$t> {
154                let a = self.0; let (d, r) = (a / b, a % b);
155                iif![2 * r.abs() >= b.abs();
156                    iif![(a > 0) == (b > 0); Int(d + 1); Int(d - 1)]; Int(d)]
157            }
158
159            /// Returns the quotient, rounding ties towards zero.
160            /// # Examples
161            /// ```
162            /// # use devela::Int;
163            #[doc = "assert_eq![Int(7_" $t ").div_ties_towards(3), Int(2)]; // == 2.33…"]
164            #[doc = "assert_eq![Int(7_" $t ").div_ties_towards(-3), Int(-2)];"]
165            #[doc = "assert_eq![Int(-7_" $t ").div_ties_towards(3), Int(-2)];"]
166            #[doc = "assert_eq![Int(-7_" $t ").div_ties_towards(-3), Int(2)];"]
167            ///
168            #[doc = "assert_eq![Int(7_" $t ").div_ties_towards(5), Int(1)]; // == 1.4"]
169            #[doc = "assert_eq![Int(6_" $t ").div_ties_towards(4), Int(1)]; // == 1.5"]
170            #[doc = "assert_eq![Int(8_" $t ").div_ties_towards(5), Int(2)]; // == 1.6"]
171            #[doc = "assert_eq![Int(5_" $t ").div_ties_towards(2), Int(2)]; // == 2.5"]
172            #[doc = "assert_eq![Int(-7_" $t ").div_ties_towards(5), Int(-1)]; // == -1.4"]
173            #[doc = "assert_eq![Int(-6_" $t ").div_ties_towards(4), Int(-1)]; // == -1.5"]
174            #[doc = "assert_eq![Int(-8_" $t ").div_ties_towards(5), Int(-2)]; // == -1.6"]
175            #[doc = "assert_eq![Int(-5_" $t ").div_ties_towards(2), Int(-2)]; // == -2.5"]
176            /// ```
177            #[must_use]
178            pub const fn div_ties_towards(self, b: $t) -> Int<$t> {
179                let a = self.0; let (d, r) = (a / b, a % b);
180                iif![2 * r.abs() > b.abs();
181                    iif![(a > 0) == (b > 0); Int(d + 1); Int(d - 1)]; Int(d)]
182            }
183
184            /// Returns the quotient, rounding ties to the nearest even number.
185            /// # Examples
186            /// ```
187            /// # use devela::Int;
188            #[doc = "assert_eq![Int(7_" $t ").div_ties_even(3), Int(2)]; // == 2.33…"]
189            #[doc = "assert_eq![Int(7_" $t ").div_ties_even(-3), Int(-2)];"]
190            #[doc = "assert_eq![Int(-7_" $t ").div_ties_even(3), Int(-2)];"]
191            #[doc = "assert_eq![Int(-7_" $t ").div_ties_even(-3), Int(2)];"]
192            ///
193            #[doc = "assert_eq![Int(7_" $t ").div_ties_even(5), Int(1)]; // == 1.4"]
194            #[doc = "assert_eq![Int(6_" $t ").div_ties_even(4), Int(2)]; // == 1.5"]
195            #[doc = "assert_eq![Int(8_" $t ").div_ties_even(5), Int(2)]; // == 1.6"]
196            #[doc = "assert_eq![Int(5_" $t ").div_ties_even(2), Int(2)]; // == 2.5"]
197            #[doc = "assert_eq![Int(-7_" $t ").div_ties_even(5), Int(-1)]; // == -1.4"]
198            #[doc = "assert_eq![Int(-6_" $t ").div_ties_even(4), Int(-2)]; // == -1.5"]
199            #[doc = "assert_eq![Int(-8_" $t ").div_ties_even(5), Int(-2)]; // == -1.6"]
200            #[doc = "assert_eq![Int(-5_" $t ").div_ties_even(2), Int(-2)]; // == -2.5"]
201            /// ```
202            #[must_use]
203            pub const fn div_ties_even(self, b: $t) -> Int<$t> {
204                let a = self.0; let (d, r) = (a / b, a % b);
205                // If the remainder is zero or the |remainder| is less than half of
206                // |b|, return the quotient.
207                iif![r == 0 || 2 * r.abs() < b.abs(); Int(d);
208                    // If the |remainder| is greater than half of b,
209                    // return the quotient + the sign of a × the sign of b.
210                    iif![2 * r.abs() > b.abs(); Int(d + a.signum() * b.signum());
211                        // If the quotient is even return it, otherwise return
212                        // the quotient + the sign of a × the sign of b.
213                        iif![d % 2 == 0; Int(d); Int(d + a.signum() * b.signum())] ] ]
214            }
215
216            /// Returns the quotient, rounding ties to the nearest odd number.
217            /// # Examples
218            /// ```
219            /// # use devela::Int;
220            #[doc = "assert_eq![Int(7_" $t ").div_ties_odd(3), Int(2)]; // == 2.33…"]
221            #[doc = "assert_eq![Int(7_" $t ").div_ties_odd(-3), Int(-2)];"]
222            #[doc = "assert_eq![Int(-7_" $t ").div_ties_odd(3), Int(-2)];"]
223            #[doc = "assert_eq![Int(-7_" $t ").div_ties_odd(-3), Int(2)];"]
224            ///
225            #[doc = "assert_eq![Int(7_" $t ").div_ties_odd(5), Int(1)]; // == 1.4"]
226            #[doc = "assert_eq![Int(6_" $t ").div_ties_odd(4), Int(1)]; // == 1.5"]
227            #[doc = "assert_eq![Int(8_" $t ").div_ties_odd(5), Int(2)]; // == 1.6"]
228            #[doc = "assert_eq![Int(5_" $t ").div_ties_odd(2), Int(3)]; // == 2.5"]
229            #[doc = "assert_eq![Int(-7_" $t ").div_ties_odd(5), Int(-1)]; // == -1.4"]
230            #[doc = "assert_eq![Int(-6_" $t ").div_ties_odd(4), Int(-1)]; // == -1.5"]
231            #[doc = "assert_eq![Int(-8_" $t ").div_ties_odd(5), Int(-2)]; // == -1.6"]
232            #[doc = "assert_eq![Int(-5_" $t ").div_ties_odd(2), Int(-3)]; // == -2.5"]
233            /// ```
234            #[must_use]
235            pub const fn div_ties_odd(self, b: $t) -> Int<$t> {
236                let a = self.0; let (d, r) = (a / b, a % b);
237                // If the remainder is zero or the |remainder| is less than half of
238                // |b|, return the quotient.
239                iif![r == 0 || 2 * r.abs() < b.abs(); Int(d);
240                    // If the |remainder| is greater than half of b,
241                    // return the quotient + the sign of a × the sign of b.
242                    iif![2 * r.abs() > b.abs(); Int(d + a.signum() * b.signum());
243                        // If the quotient is odd return it, otherwise return
244                        // the quotient + the sign of a × the sign of b.
245                        iif![d % 2 != 0; Int(d); Int(d + a.signum() * b.signum())] ] ]
246            }
247        }
248    }};
249    (
250    // implements unsigned ops
251    @unsigned $t:ty : $cap:literal : $d:literal) => { paste! {
252        #[doc = crate::doc_availability!(feature = $cap)]
253        ///
254        #[doc = "# Integer division related methods for `" $t "`\n\n"]
255        #[doc = "- [div_rem](#method.div_rem" $d ")"]
256        #[doc = "- [div_ceil](#method.div_ceil" $d ")"]
257        #[doc = "- [div_floor](#method.div_floor" $d ")"]
258        #[doc = "- [div_ties_away](#method.div_ties_away" $d ")"]
259        #[doc = "- [div_ties_towards](#method.div_ties_towards" $d ")"]
260        #[doc = "- [div_ties_even](#method.div_ties_even" $d ")"]
261        #[doc = "- [div_ties_odd](#method.div_ties_odd" $d ")"]
262        ///
263        #[cfg(feature = $cap )]
264        // #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
265        impl Int<$t> {
266            /* unsigned division */
267
268            /// Returns the truncated quotient and the remainder.
269            #[must_use]
270            pub const fn div_rem(self, b: $t) -> [Int<$t>; 2] {
271                let a = self.0; [Int(a / b), Int(a % b)]
272            }
273
274            /// Returns the quotient, rounding the result towards positive infinity.
275            #[doc = NOTATION_DIV_CEIL!()]
276            /// # Examples
277            /// ```
278            /// # use devela::Int;
279            #[doc = "assert_eq![Int(7_" $t ").div_ceil(3), Int(3)]; // == 2.33…"]
280            ///
281            #[doc = "assert_eq![Int(7_" $t ").div_ceil(5), Int(2)]; // == 1.4"]
282            #[doc = "assert_eq![Int(6_" $t ").div_ceil(4), Int(2)]; // == 1.5"]
283            #[doc = "assert_eq![Int(8_" $t ").div_ceil(5), Int(2)]; // == 1.6"]
284            #[doc = "assert_eq![Int(5_" $t ").div_ceil(2), Int(3)]; // == 2.5"]
285            /// ```
286            // unstable rust implementation for signed integers:
287            // WAIT: [int_roundings](https://github.com/rust-lang/rust/issues/88581)
288            #[must_use]
289            pub const fn div_ceil(self, b: $t) -> Int<$t> {
290                let a = self.0; let (d, r) = (a / b, a % b);
291                iif![r > 0 && b > 0; Int(d + 1); Int(d)]
292            }
293            // alternative implementation:
294            // pub const fn div_ceil(self, b: $t) -> $t {
295            //     let a = self.0; iif![a > 0 && b > 0; ((a - 1) / b) + 1; a / b ]
296            // }
297
298            /// Returns the quotient, rounding the result towards negative infinity.
299            #[doc = NOTATION_DIV_FLOOR!()]
300            /// # Examples
301            /// ```
302            /// # use devela::Int;
303            #[doc = "assert_eq![Int(7_" $t ").div_floor(3), Int(2)]; // == 2.33…"]
304            ///
305            #[doc = "assert_eq![Int(7_" $t ").div_floor(5), Int(1)]; // == 1.4"]
306            #[doc = "assert_eq![Int(6_" $t ").div_floor(4), Int(1)]; // == 1.5"]
307            #[doc = "assert_eq![Int(8_" $t ").div_floor(5), Int(1)]; // == 1.6"]
308            #[doc = "assert_eq![Int(5_" $t ").div_floor(2), Int(2)]; // == 2.5"]
309            /// ```
310            // unstable rust implementation for signed integers:
311            // WAIT: [int_roundings](https://github.com/rust-lang/rust/issues/88581)
312            #[must_use]
313            pub const fn div_floor(self, b: $t) -> Int<$t> {
314                Int(self.0 / b)
315            }
316
317            /// Returns the quotient, rounding ties away from zero.
318            /// # Examples
319            /// ```
320            /// # use devela::Int;
321            #[doc = "assert_eq![Int(7_" $t ").div_ties_away(3), Int(2)]; // == 2.33…"]
322            ///
323            #[doc = "assert_eq![Int(7_" $t ").div_ties_away(5), Int(1)]; // == 1.4"]
324            #[doc = "assert_eq![Int(6_" $t ").div_ties_away(4), Int(2)]; // == 1.5"]
325            #[doc = "assert_eq![Int(8_" $t ").div_ties_away(5), Int(2)]; // == 1.6"]
326            #[doc = "assert_eq![Int(5_" $t ").div_ties_away(2), Int(3)]; // == 2.5"]
327            /// ```
328            #[must_use]
329            pub const fn div_ties_away(self, b: $t) -> Int<$t> {
330                let a = self.0; let (d, r) = (a / b, a % b);
331                iif![2 * r >= b; iif![a > b; Int(d + 1); Int(d - 1)]; Int(d)]
332            }
333
334            /// Returns the quotient, rounding ties towards zero.
335            /// # Examples
336            /// ```
337            /// # use devela::Int;
338            #[doc = "assert_eq![Int(7_" $t ").div_ties_towards(3), Int(2)]; // == 2.33…"]
339            ///
340            #[doc = "assert_eq![Int(7_" $t ").div_ties_towards(5), Int(1)]; // == 1.4"]
341            #[doc = "assert_eq![Int(6_" $t ").div_ties_towards(4), Int(1)]; // == 1.5"]
342            #[doc = "assert_eq![Int(8_" $t ").div_ties_towards(5), Int(2)]; // == 1.6"]
343            #[doc = "assert_eq![Int(5_" $t ").div_ties_towards(2), Int(2)]; // == 2.5"]
344            /// ```
345            #[must_use]
346            pub const fn div_ties_towards(self, b: $t) -> Int<$t> {
347                let a = self.0; let (d, r) = (a / b, a % b);
348                iif![2 * r > b; Int(d + 1); Int(d)]
349            }
350
351            /// Returns the quotient, rounding ties to the nearest even number.
352            /// # Examples
353            /// ```
354            /// # use devela::Int;
355            #[doc = "assert_eq![Int(7_" $t ").div_ties_even(3), Int(2)]; // == 2.33…"]
356            ///
357            #[doc = "assert_eq![Int(7_" $t ").div_ties_even(5), Int(1)]; // == 1.4"]
358            #[doc = "assert_eq![Int(6_" $t ").div_ties_even(4), Int(2)]; // == 1.5"]
359            #[doc = "assert_eq![Int(8_" $t ").div_ties_even(5), Int(2)]; // == 1.6"]
360            #[doc = "assert_eq![Int(5_" $t ").div_ties_even(2), Int(2)]; // == 2.5"]
361            /// ```
362            #[must_use]
363            pub const fn div_ties_even(self, b: $t) -> Int<$t> {
364                let a = self.0; let (d, r) = (a / b, a % b);
365                // 1. If the remainder is zero or less than half of b, return the quotient.
366                // 2. If the remainder is greater than half of b, return the quotient + 1.
367                // 3. If the quotient is _EVEN_ return it, otherwise return the quotient + 1.
368                iif![r == 0 || 2 * r < b; Int(d);
369                    iif![2 * r > b; Int(d + 1);
370                        iif![d % 2 == 0; Int(d); Int(d + 1)]]]
371            }
372
373            /// Returns the quotient, rounding ties to the nearest even number.
374            /// # Examples
375            /// ```
376            /// # use devela::Int;
377            #[doc = "assert_eq![Int(7_" $t ").div_ties_odd(3), Int(2)]; // == 2.33…"]
378            ///
379            #[doc = "assert_eq![Int(7_" $t ").div_ties_odd(5), Int(1)]; // == 1.4"]
380            #[doc = "assert_eq![Int(6_" $t ").div_ties_odd(4), Int(1)]; // == 1.5"]
381            #[doc = "assert_eq![Int(8_" $t ").div_ties_odd(5), Int(2)]; // == 1.6"]
382            #[doc = "assert_eq![Int(5_" $t ").div_ties_odd(2), Int(3)]; // == 2.5"]
383            /// ```
384            #[must_use]
385            pub const fn div_ties_odd(self, b: $t) -> Int<$t> {
386                let a = self.0; let (d, r) = (a / b, a % b);
387                // 1. If the remainder is zero or less than half of b, return the quotient.
388                // 2. If the remainder is greater than half of b, return the quotient + 1.
389                // 3. If the quotient is _ODD_ return it, otherwise return the quotient + 1.
390                iif![r == 0 || 2 * r < b; Int(d);
391                    iif![2 * r > b; Int(d + 1);
392                        iif![d % 2 != 0; Int(d); Int(d + 1)]]]
393            }
394        }
395    }};
396}
397impl_div!();