devela/num/int/wrapper/
impl_core.rs

1// devela::num::int::wrapper::impl_core
2//
3//! Implements core methods for [`Int`].
4//
5// TOC
6// - signed|unsigned
7//   - abs
8//   - is_even
9//   - is_odd
10//   - gcd
11//   - gcd_ext
12//   - gcd_ext_euc
13//   - lcm
14//   - scale
15//   - scale_wrap
16//   - midpoint
17
18use super::super::shared_docs::*;
19#[cfg(any(feature = "_int_isize", feature = "_int_usize"))]
20use crate::isize_up;
21#[cfg(feature = "_int_usize")]
22use crate::usize_up;
23#[cfg(feature = "cast")]
24use crate::Cast;
25#[allow(unused_imports)]
26use crate::{cswap, iif, paste, unwrap, GcdReturn, Int, NumError::Overflow, NumResult as Result};
27
28/// Implements core methods for [`Int`].
29///
30/// # Args
31/// $t:    the input/output type
32/// $cap:  the capability feature enabling the given implementation. E.g "_int_u8"
33///
34/// $ut:   the unsigned type of the same size as $t (only for signed)
35/// $ucap: the feature enabling some methods related to `$ut` (signed midpoint)
36///
37/// $up:   the upcasted type to do the operations on (for lcm). E.g u8
38///
39/// $iup:  the signed upcasted type for some methods (gcd_ext). E.g. i16 (only for unsigned)
40/// $icap: the feature enabling some methods related to `$iup`. E.g "_int_i16" (only for unsigned)
41///
42/// $d:    the doclink suffix for the method name
43macro_rules! impl_core {
44    () => {
45        impl_core![signed
46            // $t :$cap         :$ut   :$ucap        |$up      |$d
47            i8    :"_int_i8"    :u8    :"_int_u8"    |i16      |"",
48            i16   :"_int_i16"   :u16   :"_int_u16"   |i32      |"-1",
49            i32   :"_int_i32"   :u32   :"_int_u32"   |i64      |"-2",
50            i64   :"_int_i64"   :u64   :"_int_u64"   |i128     |"-3",
51            i128  :"_int_i128"  :u128  :"_int_u128"  |i128     |"-4",
52            isize :"_int_isize" :usize :"_int_usize" |isize_up |"-5"
53        ];
54        impl_core![unsigned
55            // $t :$cap         :$up      |$iup     :$iucap          |$d
56            u8    :"_int_u8"    :u16      |i16      :"_int_i16"      |"-6",
57            u16   :"_int_u16"   :u32      |i32      :"_int_i32"      |"-7",
58            u32   :"_int_u32"   :u64      |i64      :"_int_i64"      |"-8",
59            u64   :"_int_u64"   :u128     |i128     :"_int_i128"     |"-9",
60            u128  :"_int_u128"  :u128     |i128     :"_int_i128"     |"-10"
61          //usize :"_int_usize" :usize_up |isize_up :"_int_isize_up" |"-11"]; // MAYBE
62        ];
63        #[cfg(target_pointer_width = "32")]
64        impl_core![unsigned usize :"_int_usize" :usize_up |isize_up :"_int_i64"  |"-11"];
65        #[cfg(target_pointer_width = "64")]
66        impl_core![unsigned usize :"_int_usize" :usize_up |isize_up :"_int_i128" |"-11"];
67    };
68    (signed $( $t:ty : $cap:literal : $ut:ty : $ucap:literal | $up:ty |$d:literal ),+) => {
69        $( impl_core![@signed   $t :$cap :$ut :$ucap :$up |$d]; )+
70    };
71    (unsigned $( $t:ty : $cap:literal : $up:ty | $iup:ty : $icap:literal |$d:literal ),+) => {
72        $( impl_core![@unsigned $t :$cap :$up |$iup :$icap |$d]; )+
73    };
74    (
75    // implements signed ops
76    @signed $t:ty : $cap:literal : $ut:ty : $ucap:literal : $up:ty |$d:literal) => { paste! {
77        #[doc = crate::doc_availability!(feature = $cap)]
78        ///
79        #[doc = "# Integer core methods for `" $t "`\n\n"]
80        #[doc = "- [abs](#method.abs" $d ")"]
81        #[doc = "- [is_even](#method.is_even" $d ")"]
82        #[doc = "- [is_odd](#method.is_odd" $d ")"]
83        #[doc = "- [gcd](#method.gcd" $d ")"]
84        #[doc = "- [gcd_ext](#method.gcd_ext" $d ")"]
85        #[doc = "- [gcd_ext_euc](#method.gcd_ext_euc" $d ")"]
86        #[doc = "- [lcm](#method.lcm" $d ")"]
87        #[doc = "- [scale](#method.scale" $d ")"]
88        #[doc = "- [scale_wrap](#method.scale_wrap" $d ")"]
89        #[doc = "- [midpoint](#method.midpoint" $d ")"]
90        ///
91        #[cfg(feature = $cap )]
92        impl Int<$t> {
93            /// Returns the absolute value of `self`.
94            #[must_use]
95            pub const fn abs(self) -> Int<$t> { Int(self.0.abs()) }
96
97            /// Returns `true` if `self` is an even number.
98            ///
99            /// # Examples
100            /// ```
101            /// # use devela::Int;
102            #[doc = "assert![Int(2_" $t ").is_even()];"]
103            #[doc = "assert![Int(-2_" $t ").is_even()];"]
104            #[doc = "assert![!Int(3_" $t ").is_even()];"]
105            #[doc = "assert![Int(0_" $t ").is_even()];"]
106            /// ```
107            #[must_use]
108            pub const fn is_even(self) -> bool { self.0 & 1 == 0 }
109
110            /// Returns `true` if `self` is an odd number.
111            ///
112            /// # Examples
113            /// ```
114            /// # use devela::Int;
115            #[doc = "assert![Int(3_" $t ").is_odd()];"]
116            #[doc = "assert![Int(-3_" $t ").is_odd()];"]
117            #[doc = "assert![!Int(2_" $t ").is_odd()];"]
118            #[doc = "assert![!Int(0_" $t ").is_odd()];"]
119            /// ```
120            #[must_use]
121            pub const fn is_odd(self) -> bool { self.0 & 1 == 1 }
122
123            /* signed gcd, lcm */
124
125            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>.
126            ///
127            /// Uses Stein's algorithm which is much more efficient to compute than Euclid's.
128            ///
129            /// # Examples
130            /// ```
131            /// # use devela::Int;
132            #[doc = "assert_eq![Int(4), Int(64_" $t ").gcd(36)];"]
133            #[doc = "assert_eq![Int(4), Int(-64_" $t ").gcd(36)];"]
134            #[doc = "assert_eq![Int(4), Int(64_" $t ").gcd(-36)];"]
135            #[doc = "assert_eq![Int(4), Int(-64_" $t ").gcd(-36)];"]
136            #[doc = "assert_eq![Int(36), Int(0_" $t ").gcd(36)];"]
137            #[doc = "assert_eq![Int(64), Int(64_" $t ").gcd(0)];"]
138            /// ```
139            #[must_use]
140            pub const fn gcd(self, b: $t) -> Int<$t> {
141                let [mut a, mut b] = [self.0.abs(), b.abs()];
142                iif![a == 0; return Int(b)];
143                iif![b == 0; return Int(a)];
144                // Let k be the greatest power of 2 dividing both a and b:
145                let k = (a | b).trailing_zeros();
146                // Divide a and b by 2 until they become odd:
147                a >>= a.trailing_zeros();
148                b >>= b.trailing_zeros();
149                // Break when a == GCD of a / 2^k:
150                while b != 0 {
151                    b >>= b.trailing_zeros();
152                    // ensure b >= a before subtraction:
153                    iif![a > b; cswap!(mut: a, b); b -= a];
154                }
155                Int(a << k)
156
157                // Euclid's algorithm:
158                // while a != b { iif![a > b; a -= b; b -= a] }; a
159            }
160
161            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>
162            /// and the Bézout coeficients.
163            ///
164            /// This version uses the extended Stein's algorithm which is much more
165            /// efficient to compute than Euclid's. It uses only simple arithmetic
166            /// operations and works by dividing the inputs by 2 until they are odd,
167            /// and then subtracting the smaller number from the larger one.
168            ///
169            /// The Bézout's coefficients are not unique, and different algorithms
170            /// can yield different coefficients that all satisfy Bézout's identity.
171            ///
172            /// Bézout's identity states that for any two integers a and b,
173            /// there exist integers x and y such that $ax + by = gcd(a, b)$.
174            ///
175            /// # Examples
176            /// ```
177            /// # use devela::Int;
178            #[doc = "let (gcd, x, y) = Int(32_" $t ").gcd_ext(36).as_tuple();"]
179            /// assert_eq!(gcd.0, 4);
180            /// assert_eq!(x.0 * 32 + y.0 * 36, gcd.0);
181            /// ```
182            pub const fn gcd_ext(self, b: $t) -> GcdReturn<Int<$t>, Int<$t>> {
183                let [mut a, mut b] = [self.0.abs(), b.abs()];
184                if a == 0 { return GcdReturn::new(Int(b), Int(0), Int(1)); }
185                if b == 0 { return GcdReturn::new(Int(a), Int(1), Int(0)); }
186
187                let mut k = 0;
188                while ((a | b) & 1) == 0 {
189                    a >>= 1;
190                    b >>= 1;
191                    k += 1;
192                }
193                let (a0, b0, mut sa, mut sb, mut ta, mut tb) = (a, b, 1, 0, 0, 1);
194
195                while (a & 1) == 0 {
196                    if (sa & 1) != 0 || (sb & 1) != 0 {
197                        sa -= b0;
198                        sb += a0;
199                    }
200                    a >>= 1;
201                    sa >>= 1;
202                    sb >>= 1;
203                }
204                while b != 0 {
205                    while (b & 1) == 0 {
206                        if (ta & 1) != 0 || (tb & 1) != 0 {
207                            ta -= b0;
208                            tb += a0;
209                        }
210                        b >>= 1;
211                        ta >>= 1;
212                        tb >>= 1;
213                    }
214                    if a > b {
215                        cswap![mut: a, b];
216                        cswap![mut: sa, ta];
217                        cswap![mut: sb, tb];
218                    }
219                    b -= a;
220                    ta -= sa;
221                    tb -= sb;
222                }
223                GcdReturn::new(Int(a << k), Int(sa), Int(sb))
224            }
225
226            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>
227            /// and the Bézout coeficients.
228            ///
229            /// This version uses the extended Euclids's algorithm, which uses a
230            /// series of euclidean divisions and works by subtracting multiples
231            /// of the smaller number from the larger one.
232            ///
233            /// The Bézout's coefficients are not unique, and different algorithms
234            /// can yield different coefficients that all satisfy Bézout's identity.
235            ///
236            /// # Examples
237            /// ```
238            /// # use devela::Int;
239            #[doc = "let (gcd, x, y) = Int(32_" $t ").gcd_ext_euc(36).as_tuple();"]
240            /// assert_eq!(gcd.0, 4);
241            /// assert_eq!(x.0 * 32 + y.0 * 36, gcd.0);
242            /// ```
243            pub const fn gcd_ext_euc(self, b: $t) -> GcdReturn<Int<$t>, Int<$t>> {
244                let a = self.0;
245                if a == 0 {
246                    GcdReturn::new(Int(b), Int(0), Int(1))
247                } else {
248                    let (g, x, y) = Int(b % a).gcd_ext_euc(a).as_tuple_copy();
249                    GcdReturn::new(g, Int(y.0 - (b / a) * x.0), x)
250                }
251            }
252
253            /// Returns the <abbr title="Least Common Multiple">LCM</abbr>.
254            ///
255            #[doc = "Performs operations internally as [`" $up "`] for the inner operations."]
256            ///
257            /// # Errors
258            /// Can [`Overflow`].
259            ///
260            /// # Examples
261            /// ```
262            /// # use devela::Int;
263            #[doc = "assert_eq![Int(12_" $t ").lcm(15), Ok(Int(60))];"]
264            #[doc = "assert_eq![Int(-12_" $t ").lcm(15), Ok(Int(60))];"]
265            #[doc = "assert_eq![Int(12_" $t ").lcm(-15), Ok(Int(60))];"]
266            /// ```
267            pub const fn lcm(self, b: $t) -> Result<Int<$t>> {
268                let (aup, bup) = (self.0 as $up, b as $up);
269                let res = (aup * bup).abs() / self.gcd(b).0 as $up;
270                iif![res <= $t::MAX as $up; Ok(Int(res as $t)); Err(Overflow(None))]
271            }
272
273            /// Returns a scaled value between `[min..=max]` to a new range `[a..=b]`.
274            ///
275            #[doc = "Performs operations internally as [`" $up "`] for the checked operations."]
276            ///
277            /// If the value lies outside of `[min..=max]` it will result in extrapolation.
278            ///
279            /// # Errors
280            /// Can [`Overflow`] for extrapolated values that can't fit the type,
281            /// and for overflowing arithmetic operations in the following formula:
282            ///
283            /// # Formula
284            #[doc = FORMULA_SCALE!()]
285            ///
286            /// # Examples
287            /// ```
288            /// # use devela::Int;
289            #[doc = "assert_eq![Ok(Int(40)), Int(60_" $t ").scale(0, 120, 30, 50)]; // interpolate"]
290            #[doc = "assert_eq![Ok(Int(112)), Int(100_" $t ").scale(0, 80, 0, 90)]; // extrapolate"]
291            /// # #[cfg(feature = "_int_i8")]
292            /// assert![Int(100_i8).scale(0, 50, 0, 90).is_err()]; // extrapolate and overflow
293            /// ```
294            #[cfg(feature = "cast")]
295            #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "cast")))]
296            pub const fn scale(self, min: $t, max: $t, a: $t, b: $t) -> Result<Int<$t>> {
297                let v = self.0 as $up;
298                let (min, max, a, b) = (min as $up, max as $up, a as $up, b as $up);
299                let b_a = iif![let Some(n) = b.checked_sub(a); n; return Err(Overflow(None))];
300                let v_min = iif![let Some(n) = v.checked_sub(min); n; return Err(Overflow(None))];
301                let mul = iif![let Some(n) = b_a.checked_mul(v_min); n; return Err(Overflow(None))];
302                let max_min = iif![let Some(n) = max.checked_sub(min); n; return Err(Overflow(None))];
303                let div = iif![let Some(n) = mul.checked_div(max_min); n; return Err(Overflow(None))];
304                let sum = iif![let Some(n) = div.checked_add(a); n; return Err(Overflow(None))];
305                match Cast(sum).[<checked_cast_to_ $t>]() {
306                    Ok(n) => Ok(Int(n)),
307                    Err(e) => Err(e),
308                }
309            }
310
311            /// Returns a scaled value between `[min..=max]` to a new range `[a..=b]`.
312            ///
313            #[doc = "Performs operations internally as [`" $up "`]."]
314            ///
315            /// If the value lies outside of `[min..=max]` it will result in extrapolation, and
316            /// if the value doesn't fit in the type it will wrap around its boundaries.
317            ///
318            /// # Panics
319            /// Could panic for large values of `i128` or `u128`.
320            ///
321            /// # Formula
322            #[doc = FORMULA_SCALE!()]
323            ///
324            /// # Examples
325            /// ```
326            /// # use devela::Int;
327            #[doc = "assert_eq![Int(40), Int(60_" $t ").scale_wrap(0, 120, 30, 50)]; // interpolate"]
328            #[doc = "assert_eq![Int(112), Int(100_" $t ").scale_wrap(0, 80, 0, 90)]; // extrapolate"]
329            /// # #[cfg(feature = "_int_i8")]
330            /// assert_eq![Int(-76), Int(100_i8).scale_wrap(0, 50, 0, 90)]; // extrapolate and wrap
331            /// ```
332            pub const fn scale_wrap(self, min: $t, max: $t, a: $t, b: $t) -> Int<$t> {
333                let v = self.0 as $up;
334                let (min, max, a, b) = (min as $up, max as $up, a as $up, b as $up);
335                Int(((b - a) * (v - min) / (max - min) + a) as $t)
336            }
337            // MAYBE: scale_saturate
338
339            /// Calculates the middle point of `self` and `other`.
340            ///
341            /// The result is always rounded towards negative infinity.
342            ///
343            /// # Examples
344            /// ```
345            /// # use devela::Int;
346            #[doc = concat!("assert_eq![Int(0_", stringify!($t), ").midpoint(4), 2];")]
347            #[doc = concat!("assert_eq![Int(0_", stringify!($t), ").midpoint(-1), -1];")]
348            #[doc = concat!("assert_eq![Int(-1_", stringify!($t), ").midpoint(0), -1];")]
349            /// ```
350            // WAIT: [num_midpoint](https://github.com/rust-lang/rust/issues/110840)
351            // NOTE: based on Rust's std implementation.
352            #[cfg(feature = $ucap )]
353            #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $ucap)))]
354            pub const fn midpoint(self, other: $t) -> Int<$t> {
355                const U: $ut = <$t>::MIN.unsigned_abs();
356
357                // Map a $t to a $ut
358                // ex: i8 [-128; 127] to [0; 255]
359                const fn map(a: $t) -> $ut { (a as $ut) ^ U }
360
361                // Map a $ut to a $t
362                // ex: u8 [0; 255] to [-128; 127]
363                const fn demap(a: $ut) -> $t { (a ^ U) as $t }
364
365                Int(demap(Int(map(self.0)).midpoint(map(other)).0))
366            }
367        }
368    }};
369    (
370    // implements unsigned ops
371    @unsigned $t:ty : $cap:literal : $up:ty | $iup:ty : $icap:literal |$d:literal) => { paste! {
372        #[doc = crate::doc_availability!(feature = $cap)]
373        ///
374        #[doc = "# Integer core methods for `" $t "`\n\n"]
375        #[doc = "- [abs](#method.abs" $d ")"]
376        #[doc = "- [is_even](#method.is_even" $d ")"]
377        #[doc = "- [is_odd](#method.is_odd" $d ")"]
378        #[doc = "- [gcd](#method.gcd" $d ")"]
379        #[doc = "- [gcd_ext](#method.gcd_ext" $d ")"]
380        #[doc = "- [gcd_ext_euc](#method.gcd_ext_euc" $d ")"]
381        #[doc = "- [lcm](#method.lcm" $d ")"]
382        #[doc = "- [scale](#method.scale" $d ")"]
383        #[doc = "- [scale_wrap](#method.scale_wrap" $d ")"]
384        #[doc = "- [midpoint](#method.midpoint" $d ")"]
385        ///
386        #[cfg(feature = $cap )]
387        impl Int<$t> {
388            /// Returns the absolute value of `self` (no-op).
389            #[must_use]
390            pub const fn abs(self) -> Int<$t> { self }
391
392            /// Returns `true` if `self` is an even number.
393            ///
394            /// # Examples
395            /// ```
396            /// # use devela::Int;
397            #[doc = "assert![Int(2_" $t ").is_even()];"]
398            #[doc = "assert![!Int(3_" $t ").is_even()];"]
399            #[doc = "assert![Int(0_" $t ").is_even()];"]
400            /// ```
401            #[must_use]
402            pub const fn is_even(self) -> bool { self.0 & 1 == 0 }
403
404            /// Returns `true` if `self` is an odd number.
405            ///
406            /// # Examples
407            /// ```
408            /// # use devela::Int;
409            #[doc = "assert![Int(3_" $t ").is_odd()];"]
410            #[doc = "assert![!Int(2_" $t ").is_odd()];"]
411            #[doc = "assert![!Int(0_" $t ").is_odd()];"]
412            /// ```
413            #[must_use]
414            pub const fn is_odd(self) -> bool { self.0 & 1 == 1 }
415
416            /* unsigned gcd, lcm */
417
418            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>.
419            ///
420            /// Uses Stein's algorithm which is much more efficient to compute than Euclid's.
421            ///
422            /// # Examples
423            /// ```
424            /// # use devela::Int;
425            #[doc = "assert_eq![Int(4), Int(64_" $t ").gcd(36)];"]
426            #[doc = "assert_eq![Int(36), Int(0_" $t ").gcd(36)];"]
427            #[doc = "assert_eq![Int(64), Int(64_" $t ").gcd(0)];"]
428            /// ```
429            #[must_use]
430            pub const fn gcd(self, mut b: $t) -> Int<$t> {
431                let mut a = self.0;
432                iif![a == 0; return Int(b)];
433                iif![b == 0; return self];
434                // Let k be the greatest power of 2 dividing both a and b:
435                let k = (a | b).trailing_zeros();
436                // Divide a and b by 2 until they become odd:
437                a >>= a.trailing_zeros();
438                b >>= b.trailing_zeros();
439                // Break when a == GCD of a / 2^k:
440                while b != 0 {
441                    b >>= b.trailing_zeros();
442                    // ensure b >= a before subtraction:
443                    iif![a > b; cswap![mut: a, b]; b -= a];
444                }
445                Int(a << k)
446
447                // Euclid's algorithm:
448                // while a != b { iif![a > b; a -= b; b -= a] }; a
449            }
450
451            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>
452            /// and the Bézout coeficients.
453            ///
454            #[doc = "Performs inner operations and returns coefficients as [`" $iup "`]."]
455            ///
456            /// This version uses the extended Stein's algorithm which is much more
457            /// efficient to compute than Euclid's. It uses only simple arithmetic
458            /// operations and works by dividing the inputs by 2 until they are odd,
459            /// and then subtracting the smaller number from the larger one.
460            ///
461            /// The Bézout's coefficients are not unique, and different algorithms
462            /// can yield different coefficients that all satisfy Bézout's identity.
463            ///
464            /// Bézout's identity states that for any two integers a and b,
465            /// there exist integers x and y such that $ax + by = gcd(a, b)$.
466            ///
467            /// # Errors
468            /// Can return [`Overflow`] for `u128`.
469            ///
470            /// # Examples
471            /// ```
472            /// # use devela::{Int, isize_up};
473            #[doc = "let (gcd, x, y) = Int(32_" $t ").gcd_ext(36).unwrap().as_tuple();"]
474            /// assert_eq!(gcd.0, 4);
475            #[doc = "assert_eq![x.0 * 32 + y.0 * 36, gcd.0 as " $iup "];"]
476            /// ```
477            #[cfg(all(feature = $icap, feature = "cast"))]
478            #[cfg_attr(feature = "nightly_doc", doc(cfg(all(feature = $icap, feature = "cast"))))]
479            pub const fn gcd_ext(self, b: $t) -> Result<GcdReturn<Int<$t>, Int<$iup>>> {
480                if self.0 == 0 { return Ok(GcdReturn::new(Int(b), Int(0), Int(1))); }
481                if b == 0 { return Ok(GcdReturn::new(self, Int(1), Int(0))); }
482
483                let mut a = unwrap![ok? Cast(self.0).[<checked_cast_to_ $iup>]()];
484                let mut b = unwrap![ok? Cast(b).[<checked_cast_to_ $iup>]()];
485
486                let mut k = 0;
487                while ((a | b) & 1) == 0 {
488                    a >>= 1;
489                    b >>= 1;
490                    k += 1;
491                }
492                let (a0, b0, mut sa, mut sb, mut ta, mut tb) = (a, b, 1, 0, 0, 1);
493
494                while (a & 1) == 0 {
495                    if (sa & 1) != 0 || (sb & 1) != 0 {
496                        sa -= b0;
497                        sb += a0;
498                    }
499                    a >>= 1;
500                    sa >>= 1;
501                    sb >>= 1;
502                }
503                while b != 0 {
504                    while (b & 1) == 0 {
505                        if (ta & 1) != 0 || (tb & 1) != 0 {
506                            ta -= b0;
507                            tb += a0;
508                        }
509                        b >>= 1;
510                        ta >>= 1;
511                        tb >>= 1;
512                    }
513                    if a > b {
514                        cswap![mut: a, b];
515                        cswap![mut: sa, ta];
516                        cswap![mut: sb, tb];
517                    }
518                    b -= a;
519                    ta -= sa;
520                    tb -= sb;
521                }
522                Ok(GcdReturn::new(Int((a << k) as $t), Int(sa), Int(sb)))
523            }
524
525            /// Returns the <abbr title="Greatest Common Divisor">GCD</abbr>
526            /// and the Bézout coeficients.
527            ///
528            #[doc = "Performs inner operations and returns coefficients as [`" $iup "`]."]
529            ///
530            /// This version uses the extended Euclids's algorithm, which uses a
531            /// series of euclidean divisions and works by subtracting multiples
532            /// of the smaller number from the larger one.
533            ///
534            /// The Bézout's coefficients are not unique, and different algorithms
535            /// can yield different coefficients that all satisfy Bézout's identity.
536            ///
537            /// # Errors
538            /// Can return [`Overflow`] for `u128`.
539            ///
540            /// # Examples
541            /// ```
542            /// # use devela::{Int, isize_up};
543            #[doc = "let (gcd, x, y) = Int(32_" $t ").gcd_ext_euc(36).unwrap().as_tuple();"]
544            /// assert_eq!(gcd.0, 4);
545            #[doc = "assert_eq![x.0 * 32 + y.0 * 36, gcd.0 as " $iup "];"]
546            /// ```
547            #[cfg(all(feature = $icap, feature = "cast"))]
548            #[cfg_attr(feature = "nightly_doc", doc(cfg(all(feature = $icap, feature = "cast"))))]
549            pub const fn gcd_ext_euc(self, b: $t) -> Result<GcdReturn<Int<$t>, Int<$iup>>> {
550                let a = unwrap![ok? Cast(self.0).[<checked_cast_to_ $iup>]()];
551                let b = unwrap![ok? Cast(b).[<checked_cast_to_ $iup>]()];
552
553                if a == 0 {
554                    Ok(GcdReturn::new(Int(b as $t), Int(0), Int(1)))
555                } else {
556                    let (g, x, y) = Int(b % a).gcd_ext_euc(a).as_tuple_copy();
557                    Ok(GcdReturn::new(Int(g.0 as $t), Int(y.0 - (b / a) * x.0), x))
558                }
559            }
560
561            /// Returns the <abbr title="Least Common Multiple">LCM</abbr>.
562            ///
563            #[doc = "Performs operations internally as [`" $up "`] for the inner operations."]
564            ///
565            /// # Errors
566            /// Can [`Overflow`].
567            ///
568            /// # Examples
569            /// ```
570            /// # use devela::Int;
571            #[doc = "assert_eq![Int(12_" $t ").lcm(15), Ok(Int(60))];"]
572            /// ```
573            pub const fn lcm(self, b: $t) -> Result<Int<$t>> {
574                let (aup, bup) = (self.0 as $up, b as $up);
575                let res = aup * bup / self.gcd(b).0 as $up;
576                iif![res <= $t::MAX as $up; Ok(Int(res as $t)); Err(Overflow(None))]
577            }
578
579            /// Returns a scaled value between `[min..=max]` to a new range `[a..=b]`.
580            ///
581            #[doc = "Performs operations internally as [`" $up "`] for the checked operations."]
582            ///
583            /// If the value lies outside of `[min..=max]` it will result in extrapolation.
584            ///
585            /// # Errors
586            /// Can [`Overflow`] for extrapolated values that can't fit the type,
587            /// and for overflowing arithmetic operations in the following formula:
588            ///
589            /// # Formula
590            #[doc = FORMULA_SCALE!()]
591            ///
592            /// # Examples
593            /// ```
594            /// # use devela::Int;
595            #[doc ="assert_eq![Ok(Int(40)), Int(60_" $t ").scale(0, 120, 30, 50)]; // interpolate"]
596            #[doc ="assert_eq![Ok(Int(112)), Int(100_" $t ").scale(0, 80, 0, 90)]; // extrapolate"]
597            /// # #[cfg(feature = "_int_u8")]
598            /// assert![Int(200_u8).scale(0, 50, 0, 90).is_err()]; // extrapolate and overflow
599            /// ```
600            #[cfg(feature = "cast")]
601            #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "cast")))]
602            pub const fn scale(self, min: $t, max: $t, a: $t, b: $t) -> Result<Int<$t>> {
603                let v = self.0 as $up;
604                let (min, max, a, b) = (min as $up, max as $up, a as $up, b as $up);
605                let b_a = iif![let Some(n) = b.checked_sub(a); n; return Err(Overflow(None))];
606                let v_min = iif![let Some(n) = v.checked_sub(min); n; return Err(Overflow(None))];
607                let mul = iif![let Some(n) = b_a.checked_mul(v_min); n; return Err(Overflow(None))];
608                let max_min = iif![let Some(n) = max.checked_sub(min); n; return Err(Overflow(None))];
609                let div = iif![let Some(n) = mul.checked_div(max_min); n; return Err(Overflow(None))];
610                let sum = iif![let Some(n) = div.checked_add(a); n; return Err(Overflow(None))];
611                match Cast(sum).[<checked_cast_to_ $t>]() {
612                    Ok(n) => Ok(Int(n)),
613                    Err(e) => Err(e),
614                }
615            }
616
617            /// Returns a scaled value between `[min..=max]` to a new range `[a..=b]`.
618            ///
619            #[doc = "Performs operations internally as [`" $up "`]."]
620            ///
621            /// If the value lies outside of `[min..=max]` it will result in extrapolation, and
622            /// if the value doesn't fit in the type it will wrap around its boundaries.
623            ///
624            /// # Panics
625            /// Could panic for large values of `i128` or `u128`.
626            ///
627            /// # Formula
628            #[doc = FORMULA_SCALE!()]
629            ///
630            /// # Examples
631            /// ```
632            /// # use devela::Int;
633            #[doc = "assert_eq![Int(40), Int(60_" $t ").scale_wrap(0, 120, 30, 50)]; // interpolate"]
634            #[doc = "assert_eq![Int(112), Int(100_" $t ").scale_wrap(0, 80, 0, 90)]; // extrapolate"]
635            /// # #[cfg(feature = "_int_u8")]
636            /// assert_eq![Int(104), Int(200_u8).scale_wrap(0, 50, 0, 90)]; // extrapolate and wrap
637            /// ```
638            pub const fn scale_wrap(self, min: $t, max: $t, a: $t, b: $t) -> Int<$t> {
639                let v = self.0 as $up;
640                let (min, max, a, b) = (min as $up, max as $up, a as $up, b as $up);
641                Int(((b - a) * (v - min) / (max - min) + a) as $t)
642            }
643            // MAYBE: scale_saturate
644
645            /// Calculates the middle point of `self` and `other`.
646            ///
647            /// The result is always rounded towards negative infinity.
648            ///
649            /// # Examples
650            /// ```
651            /// # use devela::Int;
652            #[doc = concat!("assert_eq![Int(0_", stringify!($t), ").midpoint(4), 2];")]
653            #[doc = concat!("assert_eq![Int(1_", stringify!($t), ").midpoint(4), 2];")]
654            /// ```
655            // WAIT: [num_midpoint](https://github.com/rust-lang/rust/pull/131784)
656            // NOTE: based on Rust's std implementation.
657            pub const fn midpoint(self, other: $t) -> Int<$t> {
658                // Use the well known branchless algorithm from Hacker's Delight to compute
659                // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
660                Int(((self.0 ^ other) >> 1) + (self.0 & other))
661            }
662        }
663    }};
664}
665impl_core!();