]>
git.proxmox.com Git - cargo.git/blob - vendor/num-integer/src/roots.rs
3 use traits
::checked_pow
;
7 /// Provides methods to compute an integer's square root, cube root,
8 /// and arbitrary `n`th root.
9 pub trait Roots
: Integer
{
10 /// Returns the truncated principal `n`th root of an integer
11 /// -- `if x >= 0 { ⌊ⁿ√x⌋ } else { ⌈ⁿ√x⌉ }`
13 /// This is solving for `r` in `rⁿ = x`, rounding toward zero.
14 /// If `x` is positive, the result will satisfy `rⁿ ≤ x < (r+1)ⁿ`.
15 /// If `x` is negative and `n` is odd, then `(r-1)ⁿ < x ≤ rⁿ`.
19 /// Panics if `n` is zero:
22 /// # use num_integer::Roots;
23 /// println!("can't compute ⁰√x : {}", 123.nth_root(0));
26 /// or if `n` is even and `self` is negative:
29 /// # use num_integer::Roots;
30 /// println!("no imaginary numbers... {}", (-1).nth_root(10));
36 /// use num_integer::Roots;
38 /// let x: i32 = 12345;
39 /// assert_eq!(x.nth_root(1), x);
40 /// assert_eq!(x.nth_root(2), x.sqrt());
41 /// assert_eq!(x.nth_root(3), x.cbrt());
42 /// assert_eq!(x.nth_root(4), 10);
43 /// assert_eq!(x.nth_root(13), 2);
44 /// assert_eq!(x.nth_root(14), 1);
45 /// assert_eq!(x.nth_root(std::u32::MAX), 1);
47 /// assert_eq!(std::i32::MAX.nth_root(30), 2);
48 /// assert_eq!(std::i32::MAX.nth_root(31), 1);
49 /// assert_eq!(std::i32::MIN.nth_root(31), -2);
50 /// assert_eq!((std::i32::MIN + 1).nth_root(31), -1);
52 /// assert_eq!(std::u32::MAX.nth_root(31), 2);
53 /// assert_eq!(std::u32::MAX.nth_root(32), 1);
55 fn nth_root(&self, n
: u32) -> Self;
57 /// Returns the truncated principal square root of an integer -- `⌊√x⌋`
59 /// This is solving for `r` in `r² = x`, rounding toward zero.
60 /// The result will satisfy `r² ≤ x < (r+1)²`.
64 /// Panics if `self` is less than zero:
67 /// # use num_integer::Roots;
68 /// println!("no imaginary numbers... {}", (-1).sqrt());
74 /// use num_integer::Roots;
76 /// let x: i32 = 12345;
77 /// assert_eq!((x * x).sqrt(), x);
78 /// assert_eq!((x * x + 1).sqrt(), x);
79 /// assert_eq!((x * x - 1).sqrt(), x - 1);
82 fn sqrt(&self) -> Self {
86 /// Returns the truncated principal cube root of an integer --
87 /// `if x >= 0 { ⌊∛x⌋ } else { ⌈∛x⌉ }`
89 /// This is solving for `r` in `r³ = x`, rounding toward zero.
90 /// If `x` is positive, the result will satisfy `r³ ≤ x < (r+1)³`.
91 /// If `x` is negative, then `(r-1)³ < x ≤ r³`.
96 /// use num_integer::Roots;
98 /// let x: i32 = 1234;
99 /// assert_eq!((x * x * x).cbrt(), x);
100 /// assert_eq!((x * x * x + 1).cbrt(), x);
101 /// assert_eq!((x * x * x - 1).cbrt(), x - 1);
103 /// assert_eq!((-(x * x * x)).cbrt(), -x);
104 /// assert_eq!((-(x * x * x + 1)).cbrt(), -x);
105 /// assert_eq!((-(x * x * x - 1)).cbrt(), -(x - 1));
108 fn cbrt(&self) -> Self {
113 /// Returns the truncated principal square root of an integer --
114 /// see [Roots::sqrt](trait.Roots.html#method.sqrt).
116 pub fn sqrt
<T
: Roots
>(x
: T
) -> T
{
120 /// Returns the truncated principal cube root of an integer --
121 /// see [Roots::cbrt](trait.Roots.html#method.cbrt).
123 pub fn cbrt
<T
: Roots
>(x
: T
) -> T
{
127 /// Returns the truncated principal `n`th root of an integer --
128 /// see [Roots::nth_root](trait.Roots.html#tymethod.nth_root).
130 pub fn nth_root
<T
: Roots
>(x
: T
, n
: u32) -> T
{
134 macro_rules
! signed_roots
{
138 fn nth_root(&self, n
: u32) -> Self {
140 (*self as $U
).nth_root(n
) as Self
142 assert
!(n
.is_odd(), "even roots of a negative are imaginary");
143 -((self.wrapping_neg() as $U
).nth_root(n
) as Self)
148 fn sqrt(&self) -> Self {
149 assert
!(*self >= 0, "the square root of a negative is imaginary");
150 (*self as $U
).sqrt() as Self
154 fn cbrt(&self) -> Self {
156 (*self as $U
).cbrt() as Self
158 -((self.wrapping_neg() as $U
).cbrt() as Self)
165 signed_roots
!(i8, u8);
166 signed_roots
!(i16, u16);
167 signed_roots
!(i32, u32);
168 signed_roots
!(i64, u64);
170 signed_roots
!(i128
, u128
);
171 signed_roots
!(isize, usize);
174 fn fixpoint
<T
, F
>(mut x
: T
, f
: F
) -> T
192 fn bits
<T
>() -> u32 {
193 8 * mem
::size_of
::<T
>() as u32
197 fn log2
<T
: PrimInt
>(x
: T
) -> u32 {
198 debug_assert
!(x
> T
::zero());
199 bits
::<T
>() - 1 - x
.leading_zeros()
202 macro_rules
! unsigned_roots
{
205 fn nth_root(&self, n
: u32) -> Self {
206 // Specialize small roots
208 0 => panic
!("can't find a root of degree 0!"),
210 2 => return self.sqrt(),
211 3 => return self.cbrt(),
215 // The root of values less than 2ⁿ can only be 0 or 1.
216 if bits
::<$T
>() <= n
|| *self < (1 << n
) {
217 return (*self > 0) as $T
;
220 if bits
::<$T
>() > 64 {
221 // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
222 return if *self <= core
::u64::MAX
as $T
{
223 (*self as u64).nth_root(n
) as $T
225 let lo
= (self >> n
).nth_root(n
) << 1;
227 // 128-bit `checked_mul` also involves division, but we can't always
228 // compute `hiⁿ` without risking overflow. Try to avoid it though...
229 if hi
.next_power_of_two().trailing_zeros() * n
>= bits
::<$T
>() {
230 match checked_pow(hi
, n
as usize) {
231 Some(x
) if x
<= *self => hi
,
235 if hi
.pow(n
) <= *self {
244 #[cfg(feature = "std")]
246 fn guess(x
: $T
, n
: u32) -> $T
{
247 // for smaller inputs, `f64` doesn't justify its cost.
248 if bits
::<$T
>() <= 32 || x
<= core
::u32::MAX
as $T
{
249 1 << ((log2(x
) + n
- 1) / n
)
251 ((x
as f64).ln() / f64::from(n
)).exp() as $T
255 #[cfg(not(feature = "std"))]
257 fn guess(x
: $T
, n
: u32) -> $T
{
258 1 << ((log2(x
) + n
- 1) / n
)
261 // https://en.wikipedia.org/wiki/Nth_root_algorithm
264 let y
= match checked_pow(x
, n1
as usize) {
265 Some(ax
) => self / ax
,
268 (y
+ x
* n1
as $T
) / n
as $T
270 fixpoint(guess(*self, n
), next
)
273 fn sqrt(&self) -> Self {
274 if bits
::<$T
>() > 64 {
275 // 128-bit division is slow, so do a bitwise `sqrt` until it's small enough.
276 // https://en.wikipedia.org/wiki/Integer_square_root#Using_bitwise_operations
277 return if *self <= core
::u64::MAX
as $T
{
278 (*self as u64).sqrt() as $T
280 let lo
= (self >> 2u32).sqrt() << 1;
282 if hi
* hi
<= *self {
291 return (*self > 0) as Self;
294 #[cfg(feature = "std")]
296 fn guess(x
: $T
) -> $T
{
297 (x
as f64).sqrt() as $T
300 #[cfg(not(feature = "std"))]
302 fn guess(x
: $T
) -> $T
{
303 1 << ((log2(x
) + 1) / 2)
306 // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
307 let next
= |x
: $T
| (self / x
+ x
) >> 1;
308 fixpoint(guess(*self), next
)
311 fn cbrt(&self) -> Self {
312 if bits
::<$T
>() > 64 {
313 // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
314 return if *self <= core
::u64::MAX
as $T
{
315 (*self as u64).cbrt() as $T
317 let lo
= (self >> 3u32).cbrt() << 1;
319 if hi
* hi
* hi
<= *self {
327 if bits
::<$T
>() <= 32 {
328 // Implementation based on Hacker's Delight `icbrt2`
332 let smax
= bits
::<$T
>() / 3;
333 for s
in (0..smax
+ 1).rev() {
337 let b
= 3 * (y2
+ y
) + 1;
348 return (*self > 0) as Self;
350 if *self <= core
::u32::MAX
as $T
{
351 return (*self as u32).cbrt() as $T
;
354 #[cfg(feature = "std")]
356 fn guess(x
: $T
) -> $T
{
357 (x
as f64).cbrt() as $T
360 #[cfg(not(feature = "std"))]
362 fn guess(x
: $T
) -> $T
{
363 1 << ((log2(x
) + 2) / 3)
366 // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
367 let next
= |x
: $T
| (self / (x
* x
) + x
* 2) / 3;
368 fixpoint(guess(*self), next
)
375 unsigned_roots
!(u16);
376 unsigned_roots
!(u32);
377 unsigned_roots
!(u64);
379 unsigned_roots
!(u128
);
380 unsigned_roots
!(usize);