use crate::Rational;
use crate::gaussian_rational::GaussianRational;
use core::mem::take;
use malachite_base::num::arithmetic::traits::{
ContentAndPrimitivePart, MulIPow, Pow, PowAssign, Reciprocal, Square,
};
use malachite_base::num::basic::traits::One;
use malachite_nz::integer::Integer;
fn pow_general(x: &GaussianRational, exp: u64) -> GaussianRational {
let (content, primitive) = x.content_and_primitive_part();
let (g, l) = content.into_numerator_and_denominator();
let g_pow = Integer::from(g.pow(exp));
let l_pow = Integer::from(l.pow(exp));
let primitive_pow = primitive.pow(exp);
let real_numerator = primitive_pow.real * &g_pow;
GaussianRational {
real: Rational::from_integers_ref(&real_numerator, &l_pow),
imaginary: Rational::from_integers(primitive_pow.imaginary * g_pow, l_pow),
}
}
fn pow_val(x: GaussianRational, exp: u64) -> GaussianRational {
match exp {
0 => GaussianRational::ONE,
1 => x,
2 => x.square(),
_ if x.imaginary == 0u32 => GaussianRational::from(x.real.pow(exp)),
_ if x.real == 0u32 => GaussianRational::from(x.imaginary.pow(exp)).mul_i_pow(exp),
_ => pow_general(&x, exp),
}
}
fn pow_ref(x: &GaussianRational, exp: u64) -> GaussianRational {
match exp {
0 => GaussianRational::ONE,
1 => x.clone(),
2 => x.square(),
_ if x.imaginary == 0u32 => GaussianRational::from((&x.real).pow(exp)),
_ if x.real == 0u32 => GaussianRational::from((&x.imaginary).pow(exp)).mul_i_pow(exp),
_ => pow_general(x, exp),
}
}
impl Pow<u64> for GaussianRational {
type Output = Self;
#[inline]
fn pow(self, exp: u64) -> Self {
pow_val(self, exp)
}
}
impl Pow<u64> for &GaussianRational {
type Output = GaussianRational;
#[inline]
fn pow(self, exp: u64) -> GaussianRational {
pow_ref(self, exp)
}
}
impl PowAssign<u64> for GaussianRational {
#[inline]
fn pow_assign(&mut self, exp: u64) {
*self = pow_val(take(self), exp);
}
}
impl Pow<i64> for GaussianRational {
type Output = Self;
#[inline]
fn pow(self, exp: i64) -> Self {
let power = pow_val(self, exp.unsigned_abs());
if exp >= 0 { power } else { power.reciprocal() }
}
}
impl Pow<i64> for &GaussianRational {
type Output = GaussianRational;
#[inline]
fn pow(self, exp: i64) -> GaussianRational {
let power = pow_ref(self, exp.unsigned_abs());
if exp >= 0 { power } else { power.reciprocal() }
}
}
impl PowAssign<i64> for GaussianRational {
#[inline]
fn pow_assign(&mut self, exp: i64) {
*self = take(self).pow(exp);
}
}