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!();