pow.rs 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. use std::ops::Mul;
  2. use {One, CheckedMul};
  3. /// Raises a value to the power of exp, using exponentiation by squaring.
  4. ///
  5. /// # Example
  6. ///
  7. /// ```rust
  8. /// use num_traits::pow;
  9. ///
  10. /// assert_eq!(pow(2i8, 4), 16);
  11. /// assert_eq!(pow(6u8, 3), 216);
  12. /// ```
  13. #[inline]
  14. pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
  15. if exp == 0 { return T::one() }
  16. while exp & 1 == 0 {
  17. base = base.clone() * base;
  18. exp >>= 1;
  19. }
  20. if exp == 1 { return base }
  21. let mut acc = base.clone();
  22. while exp > 1 {
  23. exp >>= 1;
  24. base = base.clone() * base;
  25. if exp & 1 == 1 {
  26. acc = acc * base.clone();
  27. }
  28. }
  29. acc
  30. }
  31. /// Raises a value to the power of exp, returning `None` if an overflow occurred.
  32. ///
  33. /// Otherwise same as the `pow` function.
  34. ///
  35. /// # Example
  36. ///
  37. /// ```rust
  38. /// use num_traits::checked_pow;
  39. ///
  40. /// assert_eq!(checked_pow(2i8, 4), Some(16));
  41. /// assert_eq!(checked_pow(7i8, 8), None);
  42. /// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
  43. /// ```
  44. #[inline]
  45. pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
  46. if exp == 0 { return Some(T::one()) }
  47. macro_rules! optry {
  48. ( $ expr : expr ) => {
  49. if let Some(val) = $expr { val } else { return None }
  50. }
  51. }
  52. while exp & 1 == 0 {
  53. base = optry!(base.checked_mul(&base));
  54. exp >>= 1;
  55. }
  56. if exp == 1 { return Some(base) }
  57. let mut acc = base.clone();
  58. while exp > 1 {
  59. exp >>= 1;
  60. base = optry!(base.checked_mul(&base));
  61. if exp & 1 == 1 {
  62. acc = optry!(acc.checked_mul(&base));
  63. }
  64. }
  65. Some(acc)
  66. }