malachite_base/num/arithmetic/
overflowing_pow.rs1use crate::num::arithmetic::traits::{OverflowingPow, OverflowingPowAssign, Parity, UnsignedAbs};
10use crate::num::basic::signeds::PrimitiveSigned;
11use crate::num::basic::unsigneds::PrimitiveUnsigned;
12use crate::num::conversion::traits::OverflowingFrom;
13use crate::num::logic::traits::BitIterable;
14
15fn overflowing_pow_unsigned<T: PrimitiveUnsigned>(x: T, exp: u64) -> (T, bool) {
16 if exp == 0 {
17 (T::ONE, false)
18 } else if x < T::TWO {
19 (x, false)
20 } else {
21 let (mut power, mut overflow) = (x, false);
22 for bit in exp.bits().rev().skip(1) {
23 overflow |= power.overflowing_square_assign();
24 if bit {
25 overflow |= power.overflowing_mul_assign(x);
26 }
27 }
28 (power, overflow)
29 }
30}
31
32fn overflowing_unsigned_to_signed_neg<
33 U: PrimitiveUnsigned,
34 S: OverflowingFrom<U> + PrimitiveSigned,
35>(
36 x: U,
37) -> (S, bool) {
38 let (signed_x, overflow) = S::overflowing_from(x);
39 if signed_x == S::MIN {
40 (signed_x, false)
41 } else {
42 (signed_x.wrapping_neg(), overflow)
43 }
44}
45
46fn overflowing_pow_signed<
47 U: PrimitiveUnsigned,
48 S: OverflowingFrom<U> + PrimitiveSigned + UnsignedAbs<Output = U>,
49>(
50 x: S,
51 exp: u64,
52) -> (S, bool) {
53 let (p_abs, overflow) = OverflowingPow::overflowing_pow(x.unsigned_abs(), exp);
54 let (p, overflow_2) = if x >= S::ZERO || exp.even() {
55 S::overflowing_from(p_abs)
56 } else {
57 overflowing_unsigned_to_signed_neg(p_abs)
58 };
59 (p, overflow || overflow_2)
60}
61
62macro_rules! impl_overflowing_pow_unsigned {
63 ($t:ident) => {
64 impl OverflowingPow<u64> for $t {
65 type Output = $t;
66
67 #[inline]
70 fn overflowing_pow(self, exp: u64) -> ($t, bool) {
71 overflowing_pow_unsigned(self, exp)
72 }
73 }
74 };
75}
76apply_to_unsigneds!(impl_overflowing_pow_unsigned);
77
78macro_rules! impl_overflowing_pow_signed {
79 ($t:ident) => {
80 impl OverflowingPow<u64> for $t {
81 type Output = $t;
82
83 #[inline]
86 fn overflowing_pow(self, exp: u64) -> ($t, bool) {
87 overflowing_pow_signed(self, exp)
88 }
89 }
90 };
91}
92apply_to_signeds!(impl_overflowing_pow_signed);
93
94macro_rules! impl_overflowing_pow_primitive_int {
95 ($t:ident) => {
96 impl OverflowingPowAssign<u64> for $t {
97 #[inline]
112 fn overflowing_pow_assign(&mut self, exp: u64) -> bool {
113 let overflow;
114 (*self, overflow) = OverflowingPow::overflowing_pow(*self, exp);
115 overflow
116 }
117 }
118 };
119}
120apply_to_primitive_ints!(impl_overflowing_pow_primitive_int);