devela/num/int/wrapper/
impl_root.rs

1// devela::num::int::wrapper::impl_root
2//
3//! Implements root related methods for [`Int`].
4//
5// TOC
6// - signed|unsigned:
7// - is_square
8// - sqrt_ceil
9// - sqrt_floor
10// - sqrt_round
11// - is_power TODO
12// - root_ceil
13// - root_floor
14// - root_round TODO
15
16use super::super::shared_docs::*;
17#[cfg(any(feature = "_int_isize", feature = "_int_usize"))]
18use crate::isize_up;
19#[cfg(feature = "_int_usize")]
20use crate::usize_up;
21#[allow(unused_imports, reason = "various reasons")]
22use crate::NumError::{self, NonNegativeRequired, NonZeroRequired, Overflow};
23use crate::{iif, num::upcasted_op, paste, Int, NumResult as Result};
24
25// helper function to be called from the cold path branch when nth == 0 in root_*.
26#[cold] #[inline(never)] #[rustfmt::skip] #[cfg(_int··)]
27const fn cold_err_zero<T>() -> Result<T> { Err(NonZeroRequired) }
28// helper function to be called from the cold path branches with an ok result.
29#[cold] #[inline(never)] #[rustfmt::skip] #[cfg(_int··)]
30const fn cold_ok_int<T>(t: T) -> Result<T> { Ok(t) }
31
32/// Implements root related methods for [`Int`].
33///
34/// # Args
35/// $t:   the input/output type. E.g. i8.
36/// $up:  the upcasted input/output type. E.g. i16.
37/// $cap: the capability feature that enables the given implementation. E.g "_int_i8".
38/// $cmp: the feature that enables the given implementation. E.g "_cmp_i8".
39///
40/// $d:   the doclink suffix for the method name
41macro_rules! impl_root {
42    () => {
43        impl_root![signed
44            i8    |i16      :"_int_i8"    :"_cmp_i8"     |"",
45            i16   |i32      :"_int_i16"   :"_cmp_i16"    |"-1",
46            i32   |i64      :"_int_i32"   :"_cmp_i32"    |"-2",
47            i64   |i128     :"_int_i64"   :"_cmp_i64"    |"-3",
48            i128  |i128     :"_int_i128"  :"_cmp_i128"   |"-4",
49            isize |isize_up :"_int_isize" :"_cmp_isize"  |"-5"
50        ];
51        impl_root![unsigned
52            u8    |u16      :"_int_u8"    :"_cmp_u8"     |"-6",
53            u16   |u32      :"_int_u16"   :"_cmp_u16"    | "-7",
54            u32   |u64      :"_int_u32"   :"_cmp_u32"    | "-8",
55            u64   |u128     :"_int_u64"   :"_cmp_u64"    | "-9",
56            u128  |u128     :"_int_u128"  :"_cmp_u128"   | "-10",
57            usize |usize_up :"_int_usize" /*_cmp_usize*/ | "-11" // always available
58        ];
59    };
60    (signed $( $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal ),+) => {
61        $( impl_root![@signed $t|$up:$cap $(:$cmp)? | $d]; )+
62    };
63    (unsigned $( $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal ),+) => {
64        $( impl_root![@unsigned $t|$up:$cap $(:$cmp)? | $d]; )+
65    };
66    (
67    // implements signed ops
68    @signed $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal) => { paste! {
69        /* sqrt (signed) */
70
71        #[doc = crate::doc_availability!(feature = $cap)]
72        ///
73        #[doc = "# Integer root related methods for `" $t "`\n\n"]
74        #[doc = "- [is_square](#method.is_square" $d ")"]
75        #[doc = "- [sqrt_ceil](#method.sqrt_ceil" $d ")"]
76        #[doc = "- [sqrt_floor](#method.sqrt_floor" $d ")"]
77        #[doc = "- [sqrt_round](#method.sqrt_round" $d ")"]
78        #[doc = "- [root_ceil](#method.root_ceil" $d ")"]
79        #[doc = "- [root_floor](#method.root_floor" $d ")"]
80        #[cfg(feature = $cap )]
81        impl Int<$t> {
82            /// Returns `true` if it's a perfect square.
83            ///
84            /// Returns `false` otherwise, which includes all negative values.
85            #[doc = FORMULA_IS_SQUARE!()]
86            /// # Examples
87            /// ```
88            /// # use devela::Int;
89            #[doc="assert_eq![Int(12_" $t ").is_square(), false];"]
90            #[doc="assert_eq![Int(13_" $t ").is_square(), false];"]
91            #[doc="assert_eq![Int(16_" $t ").is_square(), true];"]
92            #[doc="assert_eq![Int(20_" $t ").is_square(), false];"]
93            #[doc="assert_eq![Int(21_" $t ").is_square(), false];"]
94            #[doc="assert_eq![Int(-16_" $t ").is_square(), false];"]
95            /// ```
96            $(
97            /// # Features
98            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
99            #[cfg(feature = $cmp)]
100            )? // $cmp
101            #[must_use]
102            pub const fn is_square(self) -> bool {
103                let a = self.0;
104                iif![let Ok(sqrt) = self.sqrt_floor(); sqrt.0 * sqrt.0 == a; false]
105            }
106            $( // $cmp
107            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
108            pub fn is_square(self) -> bool {
109                let a = self.0;
110                iif![let Ok(sqrt) = self.sqrt_floor(); sqrt.0 * sqrt.0 == a; false]
111            }
112            )?
113
114            /// Returns the ceiled integer square root.
115            /// # Errors
116            /// Returns [`NonNegativeRequired`] if `self` is negative.
117            /// # Formulation
118            #[doc = ALGORITHM_SQRT_CEIL!()]
119            /// # Examples
120            /// ```
121            /// # use devela::{Int, NumError::NonNegativeRequired};
122            #[doc="assert_eq![Int(12_" $t ").sqrt_ceil(), Ok(Int(4))];"]
123            #[doc="assert_eq![Int(13_" $t ").sqrt_ceil(), Ok(Int(4))];"]
124            #[doc="assert_eq![Int(16_" $t ").sqrt_ceil(), Ok(Int(4))];"]
125            #[doc="assert_eq![Int(20_" $t ").sqrt_ceil(), Ok(Int(5))];"]
126            #[doc="assert_eq![Int(21_" $t ").sqrt_ceil(), Ok(Int(5))];"]
127            #[doc="assert_eq![Int(-4_" $t ").sqrt_ceil(), Err(NonNegativeRequired)];"]
128            /// ```
129            $(
130            /// # Features
131            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
132            #[cfg(feature = $cmp)]
133            )? // $cmp
134            pub const fn sqrt_ceil(self) -> Result<Int<$t>> {
135                let a = self.0;
136                if let Ok(floor) = self.sqrt_floor() {
137                    iif![floor.0 * floor.0 == a; Ok(floor); Ok(Int(floor.0 + 1))]
138                } else {
139                    Err(NonNegativeRequired)
140                }
141            }
142            $( // $ cmp
143            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
144            pub fn sqrt_ceil(self) -> Result<Int<$t>> {
145                let a = self.0;
146                if let Ok(floor) = self.sqrt_floor() {
147                    iif![floor.0 * floor.0 == a; Ok(floor); Ok(Int(floor.0 + 1))]
148                } else {
149                    Err(NonNegativeRequired)
150                }
151            }
152            )?
153
154            /// Returns the floored integer square root.
155            ///
156            /// # Errors
157            /// Returns [`NonNegativeRequired`] if `self` is negative.
158            ///
159            /// # Formulation
160            #[doc = ALGORITHM_SQRT_FLOOR!()]
161            /// # Examples
162            /// ```
163            /// # use devela::{Int, NumError::NonNegativeRequired};
164            #[doc="assert_eq![Int(12_" $t ").sqrt_floor(), Ok(Int(3))];"]
165            #[doc="assert_eq![Int(13_" $t ").sqrt_floor(), Ok(Int(3))];"]
166            #[doc="assert_eq![Int(16_" $t ").sqrt_floor(), Ok(Int(4))];"]
167            #[doc="assert_eq![Int(20_" $t ").sqrt_floor(), Ok(Int(4))];"]
168            #[doc="assert_eq![Int(21_" $t ").sqrt_floor(), Ok(Int(4))];"]
169            #[doc="assert_eq![Int(-4_" $t ").sqrt_floor(), Err(NonNegativeRequired)];"]
170            /// ```
171            $(
172            /// # Features
173            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
174            #[cfg(feature = $cmp)]
175            )? // $cmp
176            pub const fn sqrt_floor(self) -> Result<Int<$t>> {
177                let a = crate::Compare(self.0).min(<$t>::MAX - 1); // avoid overflow on MAX
178                if a.is_negative() {
179                    Err(NonNegativeRequired)
180                } else if a < 2 {
181                    Ok(self)
182                } else {
183                    let (mut x, mut y) = (a, (a + a / a) / 2);
184                    while y < x {
185                        x = y;
186                        y = (x + a / x) / 2;
187                    }
188                    Ok(Int(x))
189                }
190            }
191            $( // $cmp
192            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
193            pub fn sqrt_floor(self) -> Result<Int<$t>> {
194                let a = self.0.min(<$t>::MAX - 1); // avoid overflow on MAX
195                if a.is_negative() {
196                    Err(NonNegativeRequired)
197                } else if a < 2 {
198                    Ok(self)
199                } else {
200                    let (mut x, mut y) = (a, (a + a / a) / 2);
201                    while y < x {
202                        x = y;
203                        y = (x + a / x) / 2;
204                    }
205                    Ok(Int(x))
206                }
207            }
208            )?
209
210            /// Returns the rounded integer square root.
211            ///
212            #[doc = "Performs operations internally as [`" $up "`]."]
213            ///
214            /// # Features
215            /// Uses `unsafe_hint` for performance optimizations with upcasted arithmetic.
216            ///
217            /// # Errors
218            /// Returns [`NonNegativeRequired`] if `self` is negative, or possibly [`Overflow`]
219            /// if there's no larger type to upcast and the value is close to its maximum.
220            /// # Formulation
221            #[doc = ALGORITHM_SQRT_ROUND!()]
222            /// # Examples
223            /// ```
224            /// # use devela::{Int, NumError::NonNegativeRequired};
225            #[doc="assert_eq![Int(12_" $t ").sqrt_round(), Ok(Int(3))];"]
226            #[doc="assert_eq![Int(13_" $t ").sqrt_round(), Ok(Int(4))];"]
227            #[doc="assert_eq![Int(16_" $t ").sqrt_round(), Ok(Int(4))];"]
228            #[doc="assert_eq![Int(20_" $t ").sqrt_round(), Ok(Int(4))];"]
229            #[doc="assert_eq![Int(21_" $t ").sqrt_round(), Ok(Int(5))];"]
230            #[doc="assert_eq![Int(-4_" $t ").sqrt_round(), Err(NonNegativeRequired)];"]
231            /// ```
232            pub const fn sqrt_round(self) -> Result<Int<$t>> {
233                let a = self.0 as $up;
234                if a.is_negative() {
235                    Err(NonNegativeRequired)
236                } else if a < 2 {
237                    Ok(self)
238                } else {
239                    // sqrt_floor
240                    let sum = upcasted_op![add_err(a, a / a) $t => $up];
241                    let (mut x, mut y) = (a, sum / 2);
242                    while y < x {
243                        x = y;
244                        let sum = upcasted_op![add_err(x, a / x) $t => $up];
245                        y = sum / 2;
246                    }
247                    // do we have to round up?
248                    let mul = upcasted_op![mul_err(x, x) $t => $up];
249                    iif![a - mul >= (x + 1) * (x + 1) - a; Ok(Int(x as $t + 1)); Ok(Int(x as $t))]
250                }
251            }
252
253            /* root (signed) */
254
255            /// Returns the ceiled integer `nth` root.
256            ///
257            #[doc = FORMULA_ROOT_CEIL_SIGNED!()]
258            ///
259            /// # Errors
260            /// Returns [`NonZeroRequired`] if `nth` is 0, or
261            /// [`NonNegativeRequired`] if `self` is negative and `nth` is even.
262            ///
263            /// # Examples
264            /// ```
265            /// # use devela::{Int, NumError::NonNegativeRequired};
266            #[doc="assert_eq![Int(48_" $t ").root_ceil(4), Ok(Int(3))];"]
267            #[doc="assert_eq![Int(70_" $t ").root_ceil(4), Ok(Int(3))];"]
268            #[doc="assert_eq![Int(81_" $t ").root_ceil(4), Ok(Int(3))];"]
269            #[doc="assert_eq![Int(88_" $t ").root_ceil(4), Ok(Int(4))];"]
270            #[doc="assert_eq![Int(114_" $t ").root_ceil(4), Ok(Int(4))];"]
271            #[doc="assert_eq![Int(-81" $t ").root_ceil(4), Err(NonNegativeRequired)];"]
272            #[doc="assert_eq![Int(" $t "::MAX).root_ceil(1), Ok(Int(" $t "::MAX))];"]
273            /// ```
274            /// # Formulation
275            /// ## Piece-wise
276            #[doc = PIECEWISE_ROOT_CEIL_SIGNED!()]
277            /// ## Algorithm
278            #[doc = ALGORITHM_ROOT_CEIL_SIGNED!()]
279            pub const fn root_ceil(self, nth: u32) -> Result<Int<$t>> {
280                if nth == 0 {
281                    cold_err_zero()
282                } else if nth == 1 {
283                    cold_ok_int(self)
284                } else if self.0 == 0 {
285                    cold_ok_int(Int(0))
286                } else if self.0 < 0 && nth % 2 == 0 {
287                    Err(NonNegativeRequired)
288                } else {
289                    let mut x = 1 as $t;
290                    let positive_base = self.0.abs();
291                    while let Some(val) = x.checked_pow(nth) {
292                        if val > positive_base { break; }
293                        x += 1;
294                    }
295                    let floor_root = x - 1;
296                    let ceil_root = if floor_root.pow(nth) == positive_base {
297                        floor_root
298                    } else {
299                        floor_root + 1
300                    };
301                    Ok(Int(ceil_root * self.0.signum()))
302                }
303            }
304
305            /// Returns the floored integer `nth` root.
306            ///
307            #[doc = FORMULA_ROOT_FLOOR_SIGNED!()]
308            ///
309            /// # Errors
310            /// Returns [`NonZeroRequired`] if `nth` is 0, or
311            /// [`NonNegativeRequired`] if `self` is negative and `nth` is even.
312            ///
313            /// # Examples
314            /// ```
315            /// # use devela::{Int, NumError::NonNegativeRequired};
316            #[doc="assert_eq![Int(48_" $t ").root_floor(4), Ok(Int(2))];"]
317            #[doc="assert_eq![Int(70_" $t ").root_floor(4), Ok(Int(2))];"]
318            #[doc="assert_eq![Int(81_" $t ").root_floor(4), Ok(Int(3))];"]
319            #[doc="assert_eq![Int(88_" $t ").root_floor(4), Ok(Int(3))];"]
320            #[doc="assert_eq![Int(114_" $t ").root_floor(4), Ok(Int(3))];"]
321            #[doc="assert_eq![Int(-81_" $t ").root_floor(4), Err(NonNegativeRequired)];"]
322            #[doc="assert_eq![Int(" $t "::MAX).root_floor(1), Ok(Int(" $t "::MAX))];"]
323            /// ```
324            /// # Formulations
325            /// ## Piece-wise
326            #[doc = PIECEWISE_ROOT_FLOOR_SIGNED!()]
327            /// ## Algorithm
328            #[doc = ALGORITHM_ROOT_FLOOR_SIGNED!()]
329            pub const fn root_floor(self, nth: u32) -> Result<Int<$t>> {
330                if nth == 0 {
331                    cold_err_zero()
332                } else if nth == 1 {
333                    cold_ok_int(self)
334                } else if self.0 == 0 {
335                    cold_ok_int(Int(0))
336                } else if self.0 < 0 && nth % 2 == 0 {
337                    Err(NonNegativeRequired)
338                } else {
339                    let mut x = 1 as $t;
340                    let positive_base = self.0.abs();
341                    while let Some(val) = x.checked_pow(nth) {
342                        if val > positive_base { break; }
343                        x += 1;
344                    }
345                    Ok(Int((x - 1) * self.0.signum()))
346                }
347            }
348
349            // TODO: root_round
350        }
351    }};
352    (
353    // implements unsigned ops
354    @unsigned $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal) => { paste! {
355        #[doc = crate::doc_availability!(feature = $cap)]
356        ///
357        #[doc = "# Integer root related methods for `" $t "`\n\n"]
358        #[doc = "- [is_square](#method.is_square" $d ")"]
359        #[doc = "- [sqrt_ceil](#method.sqrt_ceil" $d ")"]
360        #[doc = "- [sqrt_floor](#method.sqrt_floor" $d ")"]
361        #[doc = "- [sqrt_round](#method.sqrt_round" $d ")"]
362        #[doc = "- [root_ceil](#method.root_ceil" $d ")"]
363        #[doc = "- [root_floor](#method.root_floor" $d ")"]
364        #[cfg(feature = $cap )]
365        impl Int<$t> {
366            /* sqrt (unsigned) */
367
368            /// Returns `true` if it's a perfect square, false otherwise.
369            /// # Formulation
370            #[doc = FORMULA_IS_SQUARE!()]
371            /// # Examples
372            /// ```
373            /// # use devela::Int;
374            #[doc="assert_eq![Int(12_" $t ").is_square(), false];"]
375            #[doc="assert_eq![Int(13_" $t ").is_square(), false];"]
376            #[doc="assert_eq![Int(16_" $t ").is_square(), true];"]
377            #[doc="assert_eq![Int(20_" $t ").is_square(), false];"]
378            #[doc="assert_eq![Int(21_" $t ").is_square(), false];"]
379            /// ```
380            $(
381            /// # Features
382            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
383            #[cfg(feature = $cmp)]
384            )? // $cmp
385            #[must_use]
386            pub const fn is_square(self) -> bool {
387                let a = self.0;
388                let sqrt = self.sqrt_floor();
389                sqrt.0 * sqrt.0 == a
390            }
391            $( // $cmp
392            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
393            pub fn is_square(self) -> bool {
394                let a = self.0;
395                let sqrt = self.sqrt_floor();
396                sqrt.0 * sqrt.0 == a
397            }
398            )?
399
400            /// Returns the ceiled integer square root.
401            ///
402            /// # Formulation
403            #[doc = ALGORITHM_SQRT_CEIL!()]
404            ///
405            /// # Examples
406            /// ```
407            /// # use devela::Int;
408            #[doc="assert_eq![Int(12_" $t ").sqrt_ceil(), Int(4)];"]
409            #[doc="assert_eq![Int(13_" $t ").sqrt_ceil(), Int(4)];"]
410            #[doc="assert_eq![Int(16_" $t ").sqrt_ceil(), Int(4)];"]
411            #[doc="assert_eq![Int(20_" $t ").sqrt_ceil(), Int(5)];"]
412            #[doc="assert_eq![Int(21_" $t ").sqrt_ceil(), Int(5)];"]
413            /// ```
414            $(
415            /// # Features
416            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
417            #[cfg(feature = $cmp)]
418            )? // $cmp
419            #[must_use]
420            pub const fn sqrt_ceil(self) -> Int<$t> {
421                let a = self.0; let floor = self.sqrt_floor();
422                iif![floor.0 * floor.0 == a; floor; Int(floor.0 + 1)]
423            }
424            $( // $cmp
425            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
426            pub fn sqrt_ceil(self) -> Int<$t> {
427                let a = self.0; let floor = self.sqrt_floor();
428                iif![floor.0 * floor.0 == a; floor; Int(floor.0 + 1)]
429            }
430            )?
431
432            /// Returns the floored integer square root.
433            ///
434            /// # Formulation
435            #[doc = ALGORITHM_SQRT_FLOOR!()]
436            ///
437            /// # Examples
438            /// ```
439            /// # use devela::Int;
440            #[doc="assert_eq![Int(12_" $t ").sqrt_floor(), Int(3)];"]
441            #[doc="assert_eq![Int(13_" $t ").sqrt_floor(), Int(3)];"]
442            #[doc="assert_eq![Int(16_" $t ").sqrt_floor(), Int(4)];"]
443            #[doc="assert_eq![Int(20_" $t ").sqrt_floor(), Int(4)];"]
444            #[doc="assert_eq![Int(21_" $t ").sqrt_floor(), Int(4)];"]
445            /// ```
446            $(
447            /// # Features
448            #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
449            #[cfg(feature = $cmp)]
450            )? // $cmp
451            #[must_use]
452            pub const fn sqrt_floor(self) -> Int<$t> {
453                let a = crate::Compare(self.0).min(<$t>::MAX - 1); // avoid overflow on MAX
454                if a < 2 {
455                    self
456                } else {
457                    let (mut x, mut y) = (a, (a + a / a) / 2);
458                    while y < x {
459                        x = y;
460                        y = (x + a / x) / 2;
461                    }
462                    Int(x)
463                }
464            }
465            $( // $cmp
466            #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
467            pub fn sqrt_floor(self) -> Int<$t> {
468                let a = self.0.min(<$t>::MAX - 1); // avoid overflow on MAX
469                if a < 2 {
470                    self
471                } else {
472                    let (mut x, mut y) = (a, (a + a / a) / 2);
473                    while y < x {
474                        x = y;
475                        y = (x + a / x) / 2;
476                    }
477                    Int(x)
478                }
479            }
480            )?
481
482            /// Returns the rounded integer square root.
483            ///
484            #[doc = "Performs operations internally as [`" $up "`]."]
485            ///
486            /// # Features
487            /// Uses `unsafe_hint` for performance optimizations with upcasted arithmetic.
488            ///
489            /// # Errors
490            /// Can returns [`Overflow`] if there's no larger type to upcast and the value
491            /// is close to its maximum.
492            ///
493            /// # Formulation
494            #[doc = ALGORITHM_SQRT_ROUND!()]
495            /// # Examples
496            /// ```
497            /// # use devela::Int;
498            #[doc="assert_eq![Int(12_" $t ").sqrt_round(), Ok(Int(3))];"]
499            #[doc="assert_eq![Int(13_" $t ").sqrt_round(), Ok(Int(4))];"]
500            #[doc="assert_eq![Int(16_" $t ").sqrt_round(), Ok(Int(4))];"]
501            #[doc="assert_eq![Int(20_" $t ").sqrt_round(), Ok(Int(4))];"]
502            #[doc="assert_eq![Int(21_" $t ").sqrt_round(), Ok(Int(5))];"]
503            /// ```
504            pub const fn sqrt_round(self) -> Result<Int<$t>> {
505                let a = self.0 as $up;
506                if a < 2 {
507                    Ok(self)
508                } else {
509                    // sqrt_floor
510                    let sum = upcasted_op![add_err(a, a / a) $t => $up];
511                    let (mut x, mut y) = (a, sum / 2);
512                    while y < x {
513                        x = y;
514                        let sum = upcasted_op![add_err(x, a / x) $t => $up];
515                        y = sum / 2;
516                    }
517                    // do we have to round up?
518                    let mul = upcasted_op![mul_err(x, x) $t => $up];
519                    iif![a - mul >= (x + 1) * (x + 1) - a; Ok(Int(x as $t + 1)); Ok(Int(x as $t))]
520                }
521            }
522
523            /* root (unsigned) */
524
525            /// Returns the ceiled integer `nth` root.
526            ///
527            #[doc = FORMULA_ROOT_CEIL_UNSIGNED!()]
528            ///
529            /// # Errors
530            /// Returns [`NonZeroRequired`] if `nth` is 0.
531            ///
532            /// # Examples
533            /// ```
534            /// # use devela::Int;
535            #[doc="assert_eq![Int(48_" $t ").root_ceil(4), Ok(Int(3))];"]
536            #[doc="assert_eq![Int(70_" $t ").root_ceil(4), Ok(Int(3))];"]
537            #[doc="assert_eq![Int(81_" $t ").root_ceil(4), Ok(Int(3))];"]
538            #[doc="assert_eq![Int(88_" $t ").root_ceil(4), Ok(Int(4))];"]
539            #[doc="assert_eq![Int(114_" $t ").root_ceil(4), Ok(Int(4))];"]
540            #[doc="assert_eq![Int(" $t "::MAX).root_ceil(1), Ok(Int(" $t "::MAX))];"]
541            /// ```
542            /// # Formulation
543            /// ## Piece-wise
544            #[doc = PIECEWISE_ROOT_CEIL_UNSIGNED!()]
545            /// ## Algorithm
546            #[doc = ALGORITHM_ROOT_CEIL_UNSIGNED!()]
547            pub const fn root_ceil(self, nth: u32) -> Result<Int<$t>> {
548                match self.root_floor(nth) {
549                    Ok(floor_root) => {
550                        if floor_root.0.pow(nth) == self.0 {
551                            Ok(floor_root)
552                        } else {
553                            Ok(Int(floor_root.0 + 1))
554                        }
555                    },
556                    Err(e) => Err(e),
557                }
558            }
559
560            /// Returns the floored integer `nth` root.
561            ///
562            #[doc = FORMULA_ROOT_FLOOR_UNSIGNED!()]
563            ///
564            /// # Errors
565            /// Returns [`NonZeroRequired`] if `nth` is 0.
566            ///
567            /// # Examples
568            /// ```
569            /// # use devela::Int;
570            #[doc="assert_eq![Int(48_" $t ").root_floor(4), Ok(Int(2))];"]
571            #[doc="assert_eq![Int(70_" $t ").root_floor(4), Ok(Int(2))];"]
572            #[doc="assert_eq![Int(81_" $t ").root_floor(4), Ok(Int(3))];"]
573            #[doc="assert_eq![Int(88_" $t ").root_floor(4), Ok(Int(3))];"]
574            #[doc="assert_eq![Int(114_" $t ").root_floor(4), Ok(Int(3))];"]
575            #[doc="assert_eq![Int(" $t "::MAX).root_floor(1), Ok(Int(" $t "::MAX))];"]
576            /// ```
577            /// # Formulations
578            /// ## Piece-wise
579            #[doc = PIECEWISE_ROOT_FLOOR_UNSIGNED!()]
580            /// ## Algorithm
581            #[doc = ALGORITHM_ROOT_FLOOR_UNSIGNED!()]
582            pub const fn root_floor(self, nth: u32) -> Result<Int<$t>> {
583                if nth == 0 {
584                    cold_err_zero()
585                } else if nth == 1 {
586                    cold_ok_int(self)
587                } else if self.0 == 0 {
588                    cold_ok_int(Int(0))
589                } else {
590                    let mut x = 1 as $t;
591                    while let Some(val) = x.checked_pow(nth) {
592                        iif![val > self.0; break];
593                        x += 1;
594                    }
595                    Ok(Int(x - 1))
596                }
597            }
598
599            // TODO: root_round
600        }
601    }};
602}
603impl_root!();