1use core::ops::{Shl, Shr};
4
5use crate::{ibig::IBig, ubig::UBig, Sign::*};
6
7impl UBig {
8 #[inline]
17 pub fn pow(&self, exp: usize) -> UBig {
18 let shift = self.trailing_zeros().unwrap_or(0);
20 let result = if shift != 0 {
21 self.repr()
22 .shr(shift)
23 .as_typed()
24 .pow(exp)
25 .into_typed()
26 .shl(exp * shift)
27 } else {
28 self.repr().pow(exp)
29 };
30 UBig(result)
31 }
32}
33
34impl IBig {
35 #[inline]
44 pub fn pow(&self, exp: usize) -> IBig {
45 let (sign, mag) = self.as_sign_repr();
46 let sign = if sign == Negative && exp % 2 == 1 {
47 Negative
48 } else {
49 Positive
50 };
51
52 let shift = mag.trailing_zeros().unwrap_or(0);
54 let result = if shift != 0 {
55 mag.shr(shift)
56 .as_typed()
57 .pow(exp)
58 .into_typed()
59 .shl(exp * shift)
60 } else {
61 mag.pow(exp)
62 };
63 IBig(result.with_sign(sign))
64 }
65}
66
67pub(crate) mod repr {
71 use dashu_base::DivRem;
72
73 use crate::{
74 arch::word::{DoubleWord, Word},
75 buffer::Buffer,
76 math::{self, bit_len, max_exp_in_word},
77 memory::{self, MemoryAllocation},
78 mul, mul_ops,
79 primitive::{extend_word, shrink_dword, split_dword},
80 repr::{
81 Repr,
82 TypedReprRef::{self, *},
83 },
84 sqr,
85 };
86
87 impl TypedReprRef<'_> {
88 pub fn pow(self, exp: usize) -> Repr {
89 match exp {
91 0 => return Repr::one(),
92 1 => return Repr::from_ref(self),
93 2 => return self.sqr(),
94 _ => {}
95 };
96
97 match self {
98 RefSmall(dword) => {
99 if let Some(word) = shrink_dword(dword) {
100 pow_word_base(word, exp)
101 } else {
102 pow_dword_base(dword, exp)
103 }
104 }
105 RefLarge(words) => pow_large_base(words, exp),
106 }
107 }
108 }
109
110 pub(crate) fn pow_word_base(base: Word, exp: usize) -> Repr {
111 debug_assert!(exp > 1);
112 match base {
113 0 => return Repr::zero(),
114 1 => return Repr::one(),
115 2 => return Repr::zero().into_typed().set_bit(exp),
116 b if b.is_power_of_two() => {
117 return Repr::zero()
118 .into_typed()
119 .set_bit(exp * base.trailing_zeros() as usize)
120 }
121 _ => {}
122 }
123
124 let (wexp, wbase) = max_exp_in_word(base);
126 if exp < wexp {
127 return Repr::from_word(base.pow(exp as u32));
128 } else if exp < 2 * wexp {
129 let pow = base.pow((exp - wexp) as u32);
130 return Repr::from_dword(extend_word(wbase) * extend_word(pow));
131 }
132
133 let (exp, exp_rem) = exp.div_rem(wexp);
135 let mut res = Buffer::allocate(exp + 1); let mut allocation = MemoryAllocation::new(
137 memory::add_layout(
138 memory::array_layout::<Word>(exp / 2 + 1), sqr::memory_requirement_exact(exp / 2 + 1),
140 ), );
142 let mut memory = allocation.memory();
143
144 let mut p = bit_len(exp) - 2;
146 let (lo, hi) = split_dword(extend_word(wbase) * extend_word(wbase));
147 res.push(lo);
148 res.push(hi);
149
150 loop {
151 if exp & (1 << p) != 0 {
152 let carry = mul::mul_word_in_place(&mut res, wbase);
153 res.push_resizing(carry); }
155 if p == 0 {
156 break;
157 }
158 p -= 1;
159
160 let (tmp, mut memory) = memory.allocate_slice_copy(&res);
162 res.fill(0);
163 res.push_zeros(res.len());
164 sqr::sqr(&mut res, tmp, &mut memory);
165 }
166
167 let pow_rem = base.pow(exp_rem as u32);
169 let carry = mul::mul_word_in_place(&mut res, pow_rem);
170 res.push_resizing(carry);
171 Repr::from_buffer(res)
172 }
173
174 pub(crate) fn pow_dword_base(base: DoubleWord, exp: usize) -> Repr {
175 debug_assert!(exp > 1);
176 debug_assert!(base > Word::MAX as DoubleWord);
177
178 let mut res = Buffer::allocate(2 * exp); let mut allocation = MemoryAllocation::new(
180 memory::add_layout(
181 memory::array_layout::<Word>(exp), sqr::memory_requirement_exact(exp),
183 ), );
185 let mut memory = allocation.memory();
186
187 let mut p = bit_len(exp) - 2;
189 let (lo, hi) = math::mul_add_carry_dword(base, base, 0);
190 let (n0, n1) = split_dword(lo);
191 res.push(n0);
192 res.push(n1);
193 let (n2, n3) = split_dword(hi);
194 res.push(n2);
195 res.push(n3);
196
197 loop {
198 if exp & (1 << p) != 0 {
199 let carry = mul::mul_dword_in_place(&mut res, base);
200 if carry > 0 {
201 let (c0, c1) = split_dword(carry);
202 res.push(c0);
203 res.push_resizing(c1); }
205 }
206 if p == 0 {
207 break;
208 }
209 p -= 1;
210
211 let (tmp, mut memory) = memory.allocate_slice_copy(&res);
213 res.fill(0);
214 res.push_zeros(res.len());
215 sqr::sqr(&mut res, tmp, &mut memory);
216 }
217
218 Repr::from_buffer(res)
219 }
220
221 pub(crate) fn pow_large_base(base: &[Word], exp: usize) -> Repr {
222 debug_assert!(exp > 1);
223 let mut p = bit_len(exp) - 2;
224 let mut res = mul_ops::repr::square_large(base);
225 loop {
226 if exp & (1 << p) != 0 {
227 res = mul_ops::repr::mul_large(res.as_slice(), base);
228 }
229 if p == 0 {
230 break;
231 }
232 p -= 1;
233 res = mul_ops::repr::square_large(res.as_slice());
234 }
235 res
236 }
237}