num_integer/roots.rs
1use crate::Integer;
2use core::mem;
3use num_traits::{checked_pow, PrimInt};
4
5/// Provides methods to compute an integer's square root, cube root,
6/// and arbitrary `n`th root.
7pub trait Roots: Integer {
8 /// Returns the truncated principal `n`th root of an integer
9 /// -- `if x >= 0 { ⌊ⁿ√x⌋ } else { ⌈ⁿ√x⌉ }`
10 ///
11 /// This is solving for `r` in `rⁿ = x`, rounding toward zero.
12 /// If `x` is positive, the result will satisfy `rⁿ ≤ x < (r+1)ⁿ`.
13 /// If `x` is negative and `n` is odd, then `(r-1)ⁿ < x ≤ rⁿ`.
14 ///
15 /// # Panics
16 ///
17 /// Panics if `n` is zero:
18 ///
19 /// ```should_panic
20 /// # use num_integer::Roots;
21 /// println!("can't compute ⁰√x : {}", 123.nth_root(0));
22 /// ```
23 ///
24 /// or if `n` is even and `self` is negative:
25 ///
26 /// ```should_panic
27 /// # use num_integer::Roots;
28 /// println!("no imaginary numbers... {}", (-1).nth_root(10));
29 /// ```
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// use num_integer::Roots;
35 ///
36 /// let x: i32 = 12345;
37 /// assert_eq!(x.nth_root(1), x);
38 /// assert_eq!(x.nth_root(2), x.sqrt());
39 /// assert_eq!(x.nth_root(3), x.cbrt());
40 /// assert_eq!(x.nth_root(4), 10);
41 /// assert_eq!(x.nth_root(13), 2);
42 /// assert_eq!(x.nth_root(14), 1);
43 /// assert_eq!(x.nth_root(std::u32::MAX), 1);
44 ///
45 /// assert_eq!(std::i32::MAX.nth_root(30), 2);
46 /// assert_eq!(std::i32::MAX.nth_root(31), 1);
47 /// assert_eq!(std::i32::MIN.nth_root(31), -2);
48 /// assert_eq!((std::i32::MIN + 1).nth_root(31), -1);
49 ///
50 /// assert_eq!(std::u32::MAX.nth_root(31), 2);
51 /// assert_eq!(std::u32::MAX.nth_root(32), 1);
52 /// ```
53 fn nth_root(&self, n: u32) -> Self;
54
55 /// Returns the truncated principal square root of an integer -- `⌊√x⌋`
56 ///
57 /// This is solving for `r` in `r² = x`, rounding toward zero.
58 /// The result will satisfy `r² ≤ x < (r+1)²`.
59 ///
60 /// # Panics
61 ///
62 /// Panics if `self` is less than zero:
63 ///
64 /// ```should_panic
65 /// # use num_integer::Roots;
66 /// println!("no imaginary numbers... {}", (-1).sqrt());
67 /// ```
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use num_integer::Roots;
73 ///
74 /// let x: i32 = 12345;
75 /// assert_eq!((x * x).sqrt(), x);
76 /// assert_eq!((x * x + 1).sqrt(), x);
77 /// assert_eq!((x * x - 1).sqrt(), x - 1);
78 /// ```
79 #[inline]
80 fn sqrt(&self) -> Self {
81 self.nth_root(2)
82 }
83
84 /// Returns the truncated principal cube root of an integer --
85 /// `if x >= 0 { ⌊∛x⌋ } else { ⌈∛x⌉ }`
86 ///
87 /// This is solving for `r` in `r³ = x`, rounding toward zero.
88 /// If `x` is positive, the result will satisfy `r³ ≤ x < (r+1)³`.
89 /// If `x` is negative, then `(r-1)³ < x ≤ r³`.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use num_integer::Roots;
95 ///
96 /// let x: i32 = 1234;
97 /// assert_eq!((x * x * x).cbrt(), x);
98 /// assert_eq!((x * x * x + 1).cbrt(), x);
99 /// assert_eq!((x * x * x - 1).cbrt(), x - 1);
100 ///
101 /// assert_eq!((-(x * x * x)).cbrt(), -x);
102 /// assert_eq!((-(x * x * x + 1)).cbrt(), -x);
103 /// assert_eq!((-(x * x * x - 1)).cbrt(), -(x - 1));
104 /// ```
105 #[inline]
106 fn cbrt(&self) -> Self {
107 self.nth_root(3)
108 }
109}
110
111/// Returns the truncated principal square root of an integer --
112/// see [Roots::sqrt](trait.Roots.html#method.sqrt).
113#[inline]
114pub fn sqrt<T: Roots>(x: T) -> T {
115 x.sqrt()
116}
117
118/// Returns the truncated principal cube root of an integer --
119/// see [Roots::cbrt](trait.Roots.html#method.cbrt).
120#[inline]
121pub fn cbrt<T: Roots>(x: T) -> T {
122 x.cbrt()
123}
124
125/// Returns the truncated principal `n`th root of an integer --
126/// see [Roots::nth_root](trait.Roots.html#tymethod.nth_root).
127#[inline]
128pub fn nth_root<T: Roots>(x: T, n: u32) -> T {
129 x.nth_root(n)
130}
131
132macro_rules! signed_roots {
133 ($T:ty, $U:ty) => {
134 impl Roots for $T {
135 #[inline]
136 fn nth_root(&self, n: u32) -> Self {
137 if *self >= 0 {
138 (*self as $U).nth_root(n) as Self
139 } else {
140 assert!(n.is_odd(), "even roots of a negative are imaginary");
141 -((self.wrapping_neg() as $U).nth_root(n) as Self)
142 }
143 }
144
145 #[inline]
146 fn sqrt(&self) -> Self {
147 assert!(*self >= 0, "the square root of a negative is imaginary");
148 (*self as $U).sqrt() as Self
149 }
150
151 #[inline]
152 fn cbrt(&self) -> Self {
153 if *self >= 0 {
154 (*self as $U).cbrt() as Self
155 } else {
156 -((self.wrapping_neg() as $U).cbrt() as Self)
157 }
158 }
159 }
160 };
161}
162
163signed_roots!(i8, u8);
164signed_roots!(i16, u16);
165signed_roots!(i32, u32);
166signed_roots!(i64, u64);
167signed_roots!(i128, u128);
168signed_roots!(isize, usize);
169
170#[inline]
171fn fixpoint<T, F>(mut x: T, f: F) -> T
172where
173 T: Integer + Copy,
174 F: Fn(T) -> T,
175{
176 let mut xn = f(x);
177 while x < xn {
178 x = xn;
179 xn = f(x);
180 }
181 while x > xn {
182 x = xn;
183 xn = f(x);
184 }
185 x
186}
187
188#[inline]
189fn bits<T>() -> u32 {
190 8 * mem::size_of::<T>() as u32
191}
192
193#[inline]
194fn log2<T: PrimInt>(x: T) -> u32 {
195 debug_assert!(x > T::zero());
196 bits::<T>() - 1 - x.leading_zeros()
197}
198
199/// 128-bit Karatsuba Square Root, using b = 2³²
200///
201/// Reference:
202/// Paul Zimmermann. Karatsuba Square Root. [Research Report] RR-3805, INRIA. 1999, pp.8.
203/// <https://inria.hal.science/inria-00072854/en/>
204#[inline]
205fn karatsuba_sqrt(n: u128) -> u128 {
206 // Algorithm SqrtRem(n = a₃b³ + a₂b² + a₁b + a₀)
207 // Input: 0 ≤ aᵢ < b with a₃ ≥ b/4
208 // Output: (s,r) such that s² ≤ n = s² + r < (s+1)²
209 debug_assert!(n.leading_zeros() < 2);
210 let a0 = n as u32 as u128;
211 let a1 = (n >> 32) as u32 as u128;
212 let a23 = n >> 64;
213
214 // (s',r') ← SqrtRem(a₃b + a₂)
215 let s1 = (a23 as u64).sqrt() as u128;
216 let r1 = a23 - s1 * s1;
217
218 // (q,u) ← DivRem(r'b + a₁, 2s')
219 let (q, u) = ((r1 << 32) | a1).div_rem(&(2 * s1));
220
221 // s ← s'b + q
222 let mut s = (s1 << 32) + q;
223
224 // r ← ub + a₀ - q²
225 // if r < 0 then
226 // r ← r + 2s - 1
227 // s ← s - 1
228 //
229 // but to avoid negatives, we compare and adjust before subtraction,
230 // and in this case we don't care about the actual remainder.
231 if ((u << 32) | a0) < q * q {
232 s -= 1;
233 }
234 s
235}
236
237macro_rules! unsigned_roots {
238 ($T:ident) => {
239 impl Roots for $T {
240 #[inline]
241 fn nth_root(&self, n: u32) -> Self {
242 fn go(a: $T, n: u32) -> $T {
243 // Specialize small roots
244 match n {
245 0 => panic!("can't find a root of degree 0!"),
246 1 => return a,
247 2 => return a.sqrt(),
248 3 => return a.cbrt(),
249 _ => (),
250 }
251
252 // The root of values less than 2ⁿ can only be 0 or 1.
253 if bits::<$T>() <= n || a < (1 << n) {
254 return (a > 0) as $T;
255 }
256
257 if bits::<$T>() > 64 {
258 // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
259 return if a <= core::u64::MAX as $T {
260 (a as u64).nth_root(n) as $T
261 } else {
262 let lo = (a >> n).nth_root(n) << 1;
263 let hi = lo + 1;
264 // 128-bit `checked_mul` also involves division, but we can't always
265 // compute `hiⁿ` without risking overflow. Try to avoid it though...
266 if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
267 match checked_pow(hi, n as usize) {
268 Some(x) if x <= a => hi,
269 _ => lo,
270 }
271 } else {
272 if hi.pow(n) <= a {
273 hi
274 } else {
275 lo
276 }
277 }
278 };
279 }
280
281 #[cfg(feature = "std")]
282 #[inline]
283 fn guess(x: $T, n: u32) -> $T {
284 // for smaller inputs, `f64` doesn't justify its cost.
285 if bits::<$T>() <= 32 || x <= core::u32::MAX as $T {
286 1 << ((log2(x) + n - 1) / n)
287 } else {
288 ((x as f64).ln() / f64::from(n)).exp() as $T
289 }
290 }
291
292 #[cfg(not(feature = "std"))]
293 #[inline]
294 fn guess(x: $T, n: u32) -> $T {
295 1 << ((log2(x) + n - 1) / n)
296 }
297
298 // https://en.wikipedia.org/wiki/Nth_root_algorithm
299 let n1 = n - 1;
300 let next = |x: $T| {
301 let y = match checked_pow(x, n1 as usize) {
302 Some(ax) => a / ax,
303 None => 0,
304 };
305 (y + x * n1 as $T) / n as $T
306 };
307 fixpoint(guess(a, n), next)
308 }
309 go(*self, n)
310 }
311
312 #[inline]
313 fn sqrt(&self) -> Self {
314 fn go(a: $T) -> $T {
315 if bits::<$T>() > 64 {
316 // 128-bit division is slow in the Babylonian method,
317 // so use 64-bit sqrt and Karatsuba if needed.
318 return if a <= core::u64::MAX as $T {
319 (a as u64).sqrt() as $T
320 } else {
321 let shift = a.leading_zeros() / 2;
322 let n = a << (shift * 2);
323 (karatsuba_sqrt(n as u128) >> shift) as $T
324 };
325 }
326
327 if a < 4 {
328 return (a > 0) as $T;
329 }
330
331 #[cfg(feature = "std")]
332 #[inline]
333 fn guess(x: $T) -> $T {
334 (x as f64).sqrt() as $T
335 }
336
337 #[cfg(not(feature = "std"))]
338 #[inline]
339 fn guess(x: $T) -> $T {
340 1 << ((log2(x) + 1) / 2)
341 }
342
343 // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
344 let next = |x: $T| (a / x + x) >> 1;
345 fixpoint(guess(a), next)
346 }
347 go(*self)
348 }
349
350 #[inline]
351 fn cbrt(&self) -> Self {
352 fn go(a: $T) -> $T {
353 if bits::<$T>() > 64 {
354 // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
355 return if a <= core::u64::MAX as $T {
356 (a as u64).cbrt() as $T
357 } else {
358 let lo = (a >> 3u32).cbrt() << 1;
359 let hi = lo + 1;
360 if hi * hi * hi <= a {
361 hi
362 } else {
363 lo
364 }
365 };
366 }
367
368 if bits::<$T>() <= 32 {
369 // Implementation based on Hacker's Delight `icbrt2`
370 let mut x = a;
371 let mut y2 = 0;
372 let mut y = 0;
373 let smax = bits::<$T>() / 3;
374 for s in (0..smax + 1).rev() {
375 let s = s * 3;
376 y2 *= 4;
377 y *= 2;
378 let b = 3 * (y2 + y) + 1;
379 if x >> s >= b {
380 x -= b << s;
381 y2 += 2 * y + 1;
382 y += 1;
383 }
384 }
385 return y;
386 }
387
388 if a < 8 {
389 return (a > 0) as $T;
390 }
391 if a <= core::u32::MAX as $T {
392 return (a as u32).cbrt() as $T;
393 }
394
395 #[cfg(feature = "std")]
396 #[inline]
397 fn guess(x: $T) -> $T {
398 (x as f64).cbrt() as $T
399 }
400
401 #[cfg(not(feature = "std"))]
402 #[inline]
403 fn guess(x: $T) -> $T {
404 1 << ((log2(x) + 2) / 3)
405 }
406
407 // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
408 let next = |x: $T| (a / (x * x) + x * 2) / 3;
409 fixpoint(guess(a), next)
410 }
411 go(*self)
412 }
413 }
414 };
415}
416
417unsigned_roots!(u8);
418unsigned_roots!(u16);
419unsigned_roots!(u32);
420unsigned_roots!(u64);
421unsigned_roots!(u128);
422unsigned_roots!(usize);