1use 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#[cold] #[inline(never)] #[rustfmt::skip] #[cfg(_int··)]
27const fn cold_err_zero<T>() -> Result<T> { Err(NonZeroRequired) }
28#[cold] #[inline(never)] #[rustfmt::skip] #[cfg(_int··)]
30const fn cold_ok_int<T>(t: T) -> Result<T> { Ok(t) }
31
32macro_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" | "-11" ];
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 @signed $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal) => { paste! {
69 #[doc = crate::doc_availability!(feature = $cap)]
72 #[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 #[doc = FORMULA_IS_SQUARE!()]
86 #[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 $(
97 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
99 #[cfg(feature = $cmp)]
100 )? #[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 $( #[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 #[doc = ALGORITHM_SQRT_CEIL!()]
119 #[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 $(
130 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
132 #[cfg(feature = $cmp)]
133 )? 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 $( #[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 #[doc = ALGORITHM_SQRT_FLOOR!()]
161 #[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 $(
172 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
174 #[cfg(feature = $cmp)]
175 )? pub const fn sqrt_floor(self) -> Result<Int<$t>> {
177 let a = crate::Compare(self.0).min(<$t>::MAX - 1); 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 $( #[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); 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 #[doc = "Performs operations internally as [`" $up "`]."]
213 #[doc = ALGORITHM_SQRT_ROUND!()]
222 #[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 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 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 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 #[doc = FORMULA_ROOT_CEIL_SIGNED!()]
258 #[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 #[doc = PIECEWISE_ROOT_CEIL_SIGNED!()]
277 #[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 #[doc = FORMULA_ROOT_FLOOR_SIGNED!()]
308 #[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 #[doc = PIECEWISE_ROOT_FLOOR_SIGNED!()]
327 #[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 }
351 }};
352 (
353 @unsigned $t:ty | $up:ty : $cap:literal $(: $cmp:literal)? | $d:literal) => { paste! {
355 #[doc = crate::doc_availability!(feature = $cap)]
356 #[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 #[doc = FORMULA_IS_SQUARE!()]
371 #[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 $(
381 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
383 #[cfg(feature = $cmp)]
384 )? #[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 $( #[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 #[doc = ALGORITHM_SQRT_CEIL!()]
404 #[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 $(
415 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
417 #[cfg(feature = $cmp)]
418 )? #[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 $( #[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 #[doc = ALGORITHM_SQRT_FLOOR!()]
436 #[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 $(
447 #[doc = "This will only be *const* if the " $cmp " feature is enabled."]
449 #[cfg(feature = $cmp)]
450 )? #[must_use]
452 pub const fn sqrt_floor(self) -> Int<$t> {
453 let a = crate::Compare(self.0).min(<$t>::MAX - 1); 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 $( #[cfg(not(feature = $cmp))] #[allow(missing_docs)]
467 pub fn sqrt_floor(self) -> Int<$t> {
468 let a = self.0.min(<$t>::MAX - 1); 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 #[doc = "Performs operations internally as [`" $up "`]."]
485 #[doc = ALGORITHM_SQRT_ROUND!()]
495 #[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 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 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 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 #[doc = FORMULA_ROOT_CEIL_UNSIGNED!()]
528 #[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 #[doc = PIECEWISE_ROOT_CEIL_UNSIGNED!()]
545 #[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 #[doc = FORMULA_ROOT_FLOOR_UNSIGNED!()]
563 #[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 #[doc = PIECEWISE_ROOT_FLOOR_UNSIGNED!()]
580 #[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 }
601 }};
602}
603impl_root!();