use crate::gaussian_integer::GaussianInteger;
use core::mem::take;
use malachite_base::num::arithmetic::traits::{MulIPow, Pow, PowAssign, Square, SquareAssign};
use malachite_base::num::basic::traits::One;
use malachite_base::num::logic::traits::{BitAccess, SignificantBits};
fn pow_general(x: &GaussianInteger, exp: u64) -> GaussianInteger {
let bits = exp.significant_bits();
let mut power = x.square();
if exp.get_bit(bits - 2) {
power *= x;
}
for i in (0..bits - 2).rev() {
power.square_assign();
if exp.get_bit(i) {
power *= x;
}
}
power
}
fn pow_val(x: GaussianInteger, exp: u64) -> GaussianInteger {
match exp {
0 => GaussianInteger::ONE,
1 => x,
2 => x.square(),
_ if x.imaginary == 0u32 => GaussianInteger::from(x.real.pow(exp)),
_ if x.real == 0u32 => GaussianInteger::from(x.imaginary.pow(exp)).mul_i_pow(exp),
_ => pow_general(&x, exp),
}
}
fn pow_ref(x: &GaussianInteger, exp: u64) -> GaussianInteger {
match exp {
0 => GaussianInteger::ONE,
1 => x.clone(),
2 => x.square(),
_ if x.imaginary == 0u32 => GaussianInteger::from((&x.real).pow(exp)),
_ if x.real == 0u32 => GaussianInteger::from((&x.imaginary).pow(exp)).mul_i_pow(exp),
_ => pow_general(x, exp),
}
}
impl Pow<u64> for GaussianInteger {
type Output = Self;
#[inline]
fn pow(self, exp: u64) -> Self {
pow_val(self, exp)
}
}
impl Pow<u64> for &GaussianInteger {
type Output = GaussianInteger;
#[inline]
fn pow(self, exp: u64) -> GaussianInteger {
pow_ref(self, exp)
}
}
impl PowAssign<u64> for GaussianInteger {
#[inline]
fn pow_assign(&mut self, exp: u64) {
*self = pow_val(take(self), exp);
}
}