use crate::num::arithmetic::traits::{
CheckedRoot, DivAssignMod, DivMod, GcdAssign, Parity, RootRem, SqrtRem,
};
use crate::num::basic::integers::USIZE_IS_U32;
use crate::num::conversion::traits::{ExactFrom, WrappingFrom};
use crate::num::factorization::primes::SMALL_PRIMES;
use crate::num::factorization::traits::{
ExpressAsPower, Factor, IsPower, IsPrime, IsSquare, Primes,
};
use crate::num::logic::traits::{SignificantBits, TrailingZeros};
const MOD63: [u8; 63] = [
7, 7, 4, 0, 5, 4, 0, 5, 6, 5, 4, 4, 0, 4, 4, 0, 5, 4, 5, 4, 4, 0, 5, 4, 0, 5, 4, 6, 7, 4, 0, 4,
4, 0, 4, 6, 7, 5, 4, 0, 4, 4, 0, 5, 4, 4, 5, 4, 0, 5, 4, 0, 4, 4, 4, 6, 4, 0, 5, 4, 0, 4, 6,
];
const MOD61: [u8; 61] = [
7, 7, 0, 3, 1, 1, 0, 0, 2, 3, 0, 6, 1, 5, 5, 1, 1, 0, 0, 1, 3, 4, 1, 2, 2, 1, 0, 3, 2, 4, 0, 0,
4, 2, 3, 0, 1, 2, 2, 1, 4, 3, 1, 0, 0, 1, 1, 5, 5, 1, 6, 0, 3, 2, 0, 0, 1, 1, 3, 0, 7,
];
const MOD44: [u8; 44] = [
7, 7, 0, 2, 3, 3, 0, 2, 2, 3, 0, 6, 7, 2, 0, 2, 3, 2, 0, 2, 3, 6, 0, 6, 2, 3, 0, 2, 2, 2, 0, 2,
6, 7, 0, 2, 3, 3, 0, 2, 2, 2, 0, 6,
];
const MOD31: [u8; 31] =
[7, 7, 3, 0, 3, 5, 4, 1, 3, 1, 1, 0, 0, 0, 1, 2, 3, 0, 1, 1, 1, 0, 0, 2, 0, 5, 4, 2, 1, 2, 6];
const MOD72: [u8; 72] = [
7, 7, 0, 0, 0, 7, 0, 7, 7, 7, 0, 7, 0, 7, 0, 0, 7, 7, 0, 7, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7,
7, 0, 0, 7, 0, 7, 0, 0, 7, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0, 7, 7, 0, 0, 7, 0, 7, 0, 7,
7, 7, 0, 7, 0, 0, 0, 7,
];
const MOD49: [u8; 49] = [
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
];
const MOD67: [u8; 67] = [
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0,
0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2,
];
const MOD79: [u8; 79] = [
4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
];
fn get_perfect_power_u32(n: u32) -> Option<(u32, u64)> {
let mut t = MOD31[(n % 31) as usize];
t &= MOD44[(n % 44) as usize];
t &= MOD61[(n % 61) as usize];
t &= MOD63[(n % 63) as usize];
if t & 1 != 0 {
let (rt, rem) = n.sqrt_rem();
if rem == 0 {
return Some((rt, 2));
}
}
if t & 2 != 0 {
let (rt, rem) = n.root_rem(3);
if rem == 0 {
return Some((rt, 3));
}
}
if t & 4 != 0 {
let (rt, rem) = n.root_rem(5);
if rem == 0 {
return Some((rt, 5));
}
}
t = MOD49[(n % 49) as usize];
t |= MOD67[(n % 67) as usize];
t |= MOD79[(n % 79) as usize];
t &= MOD72[(n % 72) as usize];
if t & 1 != 0 {
let (rt, rem) = n.root_rem(7);
if rem == 0 {
return Some((rt, 7));
}
}
if t & 2 != 0 {
let (rt, rem) = n.root_rem(11);
if rem == 0 {
return Some((rt, 11));
}
}
if t & 13 != 0 {
let (rt, rem) = n.root_rem(13);
if rem == 0 {
return Some((rt, 13));
}
}
let count = u64::from(n.trailing_zeros());
let mut n = n >> count;
if n == 1 {
return if count == 1 {
None } else {
Some((2, count))
};
}
let mut exp = 0;
while n.is_multiple_of(3) {
n /= 3;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
if count == 0 {
return Some((3, exp));
} else if count == exp {
return Some((6, exp));
} else if count == 2 * exp {
return Some((12, exp));
}
}
return None;
}
None
}
fn get_perfect_power_u32_bool(n: u32) -> bool {
let mut t = MOD31[(n % 31) as usize];
t &= MOD44[(n % 44) as usize];
t &= MOD61[(n % 61) as usize];
t &= MOD63[(n % 63) as usize];
if t & 1 != 0 && n.is_square() {
return true;
}
if t & 2 != 0 && n.root_rem(3).1 == 0 {
return true;
}
if t & 4 != 0 && n.root_rem(5).1 == 0 {
return true;
}
t = MOD49[(n % 49) as usize];
t |= MOD67[(n % 67) as usize];
t |= MOD79[(n % 79) as usize];
t &= MOD72[(n % 72) as usize];
if t & 1 != 0 && n.root_rem(7).1 == 0 {
return true;
}
if t & 2 != 0 && n.root_rem(11).1 == 0 {
return true;
}
if t & 13 != 0 && n.root_rem(13).1 == 0 {
return true;
}
let count = n.trailing_zeros();
let mut n = n >> n.trailing_zeros();
if n == 1 {
return count != 1;
}
let mut exp = 0;
while n.is_multiple_of(3) {
n /= 3;
exp += 1;
}
exp > 0 && n == 1 && exp > 1 && (count == 0 || count == exp || count == exp << 1)
}
fn get_perfect_power_u64(n: u64) -> Option<(u64, u64)> {
let mut t = MOD31[(n % 31) as usize];
t &= MOD44[(n % 44) as usize];
t &= MOD61[(n % 61) as usize];
t &= MOD63[(n % 63) as usize];
if t & 1 != 0 {
let (rt, rem) = n.sqrt_rem();
if rem == 0 {
return Some((rt, 2));
}
}
if t & 2 != 0 {
let (rt, rem) = n.root_rem(3);
if rem == 0 {
return Some((rt, 3));
}
}
if t & 4 != 0 {
let (rt, rem) = n.root_rem(5);
if rem == 0 {
return Some((rt, 5));
}
}
t = MOD49[(n % 49) as usize];
t |= MOD67[(n % 67) as usize];
t |= MOD79[(n % 79) as usize];
t &= MOD72[(n % 72) as usize];
if t & 1 != 0 {
let (rt, rem) = n.root_rem(7);
if rem == 0 {
return Some((rt, 7));
}
}
if t & 2 != 0 {
let (rt, rem) = n.root_rem(11);
if rem == 0 {
return Some((rt, 11));
}
}
if t & 13 != 0 {
let (rt, rem) = n.root_rem(13);
if rem == 0 {
return Some((rt, 13));
}
}
let count = u64::from(n.trailing_zeros());
let mut n = n >> count;
if n == 1 {
return if count == 1 {
None } else {
Some((2, count))
};
}
let mut exp = 0;
while n.is_multiple_of(3) {
n /= 3;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
if count == 0 {
return Some((3, exp));
} else if count == exp {
return Some((6, exp));
} else if count == 2 * exp {
return Some((12, exp));
}
}
return None;
}
exp = 0;
while n.is_multiple_of(5) {
n /= 5;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
if count == 0 {
return Some((5, exp));
} else if count == exp {
return Some((10, exp));
}
}
return None;
}
if count > 0 {
return None;
}
exp = 0;
while n.is_multiple_of(7) {
n /= 7;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
return Some((7, exp));
}
return None;
}
exp = 0;
while n.is_multiple_of(11) {
n /= 11;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
return Some((11, exp));
}
return None;
}
exp = 0;
while n.is_multiple_of(13) {
n /= 13;
exp += 1;
}
if exp > 0 {
if n == 1 && exp > 1 {
return Some((13, exp));
}
return None;
}
None
}
fn get_perfect_power_u64_bool(n: u64) -> bool {
let mut t = MOD31[(n % 31) as usize];
t &= MOD44[(n % 44) as usize];
t &= MOD61[(n % 61) as usize];
t &= MOD63[(n % 63) as usize];
if t & 1 != 0 && n.is_square() {
return true;
}
if t & 2 != 0 && n.root_rem(3).1 == 0 {
return true;
}
if t & 4 != 0 && n.root_rem(5).1 == 0 {
return true;
}
t = MOD49[(n % 49) as usize];
t |= MOD67[(n % 67) as usize];
t |= MOD79[(n % 79) as usize];
t &= MOD72[(n % 72) as usize];
if t & 1 != 0 && n.root_rem(7).1 == 0 {
return true;
}
if t & 2 != 0 && n.root_rem(11).1 == 0 {
return true;
}
if t & 13 != 0 && n.root_rem(13).1 == 0 {
return true;
}
let count = u64::from(n.trailing_zeros());
let mut n = n >> count;
if n == 1 {
return count != 1;
}
let mut exp = 0;
while n.is_multiple_of(3) {
n /= 3;
exp += 1;
}
if exp > 0 {
return n == 1 && exp > 1 && (count == 0 || count == exp || count == exp << 1);
}
exp = 0;
while n.is_multiple_of(5) {
n /= 5;
exp += 1;
}
if exp > 0 {
return n == 1 && exp > 1 && (count == 0 || count == exp);
}
if count > 0 {
return false;
}
exp = 0;
while n.is_multiple_of(7) {
n /= 7;
exp += 1;
}
if exp > 0 {
return n == 1 && exp > 1;
}
exp = 0;
while n.is_multiple_of(11) {
n /= 11;
exp += 1;
}
if exp > 0 {
return n == 1 && exp > 1;
}
exp = 0;
while n.is_multiple_of(13) {
n /= 13;
exp += 1;
}
n == 1 && exp > 1
}
fn get_perfect_power_u128(n: u128) -> Option<(u128, u64)> {
if let Ok(n) = u64::try_from(n) {
return get_perfect_power_u64(n).map(|(p, e)| (u128::from(p), e));
}
let mut pow_2 = TrailingZeros::trailing_zeros(n);
if pow_2 == 1 {
return None;
}
if pow_2.is_prime() {
return n.checked_root(pow_2).map(|root| (root, pow_2));
}
let mut q = n >> pow_2;
for &prime in SMALL_PRIMES[..168].iter().skip(1) {
let prime = u128::from(prime);
let (new_q, r) = q.div_mod(prime);
if r == 0 {
q = new_q;
if q.div_assign_mod(prime) != 0 {
return None; }
let mut pow_p = 2u64;
loop {
let (new_q, r) = q.div_mod(prime);
if r == 0 {
q = new_q;
pow_p += 1;
} else {
break;
}
}
pow_2.gcd_assign(pow_p);
if pow_2 == 1 {
return None; }
if q == 1 || pow_2.is_prime() {
return n.checked_root(pow_2).map(|root| (root, pow_2));
}
}
}
if pow_2 == 0 {
let bits = n.significant_bits();
for nth in u64::primes() {
if nth > bits {
return None;
}
if let Some(root) = n.checked_root(nth) {
return Some((root, nth));
}
}
} else {
for (nth, _) in pow_2.factor() {
if let Some(root) = n.checked_root(nth) {
return Some((root, nth));
}
}
}
None
}
fn get_perfect_power_u128_bool(n: u128) -> bool {
if let Ok(n) = u64::try_from(n) {
return get_perfect_power_u64_bool(n);
}
let mut pow_2 = TrailingZeros::trailing_zeros(n);
if pow_2 == 1 {
return false;
}
if pow_2.is_prime() {
return n.checked_root(pow_2).is_some();
}
let mut q = n >> pow_2;
for &prime in SMALL_PRIMES[..168].iter().skip(1) {
let prime = u128::from(prime);
let (new_q, r) = q.div_mod(prime);
if r == 0 {
q = new_q;
if q.div_assign_mod(prime) != 0 {
return false; }
let mut pow_p = 2u64;
loop {
let (new_q, r) = q.div_mod(prime);
if r == 0 {
q = new_q;
pow_p += 1;
} else {
break;
}
}
pow_2.gcd_assign(pow_p);
if pow_2 == 1 {
return false; }
if q == 1 || pow_2.is_prime() {
return n.checked_root(pow_2).is_some();
}
}
}
if pow_2 == 0 {
let bits = n.significant_bits();
for nth in u64::primes() {
if nth > bits {
return false;
}
if n.checked_root(nth).is_some() {
return true;
}
}
} else {
for (nth, _) in pow_2.factor() {
if n.checked_root(nth).is_some() {
return true;
}
}
}
false
}
fn express_as_power_u32(n: u32) -> Option<(u32, u64)> {
if n <= 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u32(n)?;
while base > 3 {
match get_perfect_power_u32(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => {
return Some((base, exp));
}
}
}
Some((base, exp))
}
fn express_as_power_u64(n: u64) -> Option<(u64, u64)> {
if n <= 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u64(n)?;
while base > 3 {
match get_perfect_power_u64(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => {
return Some((base, exp));
}
}
}
Some((base, exp))
}
fn express_as_power_u128(n: u128) -> Option<(u128, u64)> {
if n <= 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u128(n)?;
while base > 3 {
match get_perfect_power_u128(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => {
return Some((base, exp));
}
}
}
Some((base, exp))
}
fn express_as_power_i32(n: i32) -> Option<(i32, u64)> {
if n == 0 || n == 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u32(n.unsigned_abs())?;
while base > 3 {
match get_perfect_power_u32(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
if n < 0 && exp.even() {
while exp.even() {
base *= base;
exp >>= 1;
}
if exp == 1 {
return None;
}
}
let ibase = i32::exact_from(base);
Some((if n >= 0 { ibase } else { -ibase }, exp))
}
fn express_as_power_i64(n: i64) -> Option<(i64, u64)> {
if n == 0 || n == 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u64(n.unsigned_abs())?;
while base > 3 {
match get_perfect_power_u64(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
if n < 0 && exp.even() {
while exp.even() {
base *= base;
exp >>= 1;
}
if exp == 1 {
return None;
}
}
let ibase = i64::exact_from(base);
Some((if n >= 0 { ibase } else { -ibase }, exp))
}
fn express_as_power_i128(n: i128) -> Option<(i128, u64)> {
if n == 0 || n == 1 {
return Some((n, 2));
}
let (mut base, mut exp) = get_perfect_power_u128(n.unsigned_abs())?;
while base > 3 {
match get_perfect_power_u128(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
if n < 0 && exp.even() {
while exp.even() {
base *= base;
exp >>= 1;
}
if exp == 1 {
return None;
}
}
let ibase = i128::exact_from(base);
Some((if n >= 0 { ibase } else { -ibase }, exp))
}
#[inline]
fn is_power_u32(n: u32) -> bool {
n <= 1 || get_perfect_power_u32_bool(n)
}
#[inline]
fn is_power_u64(n: u64) -> bool {
n <= 1 || get_perfect_power_u64_bool(n)
}
fn is_power_i32(n: i32) -> bool {
if n == 0 || n == 1 {
return true;
}
if n > 0 {
return get_perfect_power_u32_bool(n.unsigned_abs());
}
let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u32(n.unsigned_abs()) {
(base, exp)
} else {
return false;
};
while base > 3 {
match get_perfect_power_u32(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
!exp.is_power_of_two()
}
fn is_power_i64(n: i64) -> bool {
if n == 0 || n == 1 {
return true;
}
if n > 0 {
return get_perfect_power_u64_bool(n.unsigned_abs());
}
let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u64(n.unsigned_abs()) {
(base, exp)
} else {
return false;
};
while base > 3 {
match get_perfect_power_u64(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
!exp.is_power_of_two()
}
fn is_power_i128(n: i128) -> bool {
if n == 0 || n == 1 {
return true;
}
if n > 0 {
return get_perfect_power_u128_bool(n.unsigned_abs());
}
let (mut base, mut exp) = if let Some((base, exp)) = get_perfect_power_u128(n.unsigned_abs()) {
(base, exp)
} else {
return false;
};
while base > 3 {
match get_perfect_power_u128(base) {
Some((base2, exp2)) => {
base = base2;
exp *= exp2;
}
None => break,
}
}
!exp.is_power_of_two()
}
impl ExpressAsPower for u64 {
#[inline]
fn express_as_power(&self) -> Option<(u64, u64)> {
express_as_power_u64(*self)
}
}
impl ExpressAsPower for u128 {
#[inline]
fn express_as_power(&self) -> Option<(Self, u64)> {
express_as_power_u128(*self)
}
}
impl ExpressAsPower for usize {
fn express_as_power(&self) -> Option<(Self, u64)> {
if USIZE_IS_U32 {
match express_as_power_u32(u32::wrapping_from(*self)) {
Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
_ => None,
}
} else {
match express_as_power_u64(u64::wrapping_from(*self)) {
Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
_ => None,
}
}
}
}
impl IsPower for u64 {
#[inline]
fn is_power(&self) -> bool {
is_power_u64(*self)
}
}
impl IsPower for u128 {
#[inline]
fn is_power(&self) -> bool {
get_perfect_power_u128_bool(*self)
}
}
impl IsPower for usize {
fn is_power(&self) -> bool {
if USIZE_IS_U32 {
is_power_u32(u32::wrapping_from(*self))
} else {
is_power_u64(u64::wrapping_from(*self))
}
}
}
macro_rules! impl_unsigned_32 {
($t: ident) => {
impl ExpressAsPower for $t {
fn express_as_power(&self) -> Option<($t, u64)> {
match express_as_power_u32(u32::from(*self)) {
Some((base, exp)) => Some(($t::exact_from(base), exp)),
_ => None,
}
}
}
impl IsPower for $t {
#[inline]
fn is_power(&self) -> bool {
is_power_u32(u32::from(*self))
}
}
};
}
impl_unsigned_32!(u8);
impl_unsigned_32!(u16);
impl_unsigned_32!(u32);
impl ExpressAsPower for i64 {
#[inline]
fn express_as_power(&self) -> Option<(Self, u64)> {
express_as_power_i64(*self)
}
}
impl ExpressAsPower for i128 {
#[inline]
fn express_as_power(&self) -> Option<(Self, u64)> {
express_as_power_i128(*self)
}
}
impl ExpressAsPower for isize {
fn express_as_power(&self) -> Option<(Self, u64)> {
if USIZE_IS_U32 {
match express_as_power_i32(i32::wrapping_from(*self)) {
Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
_ => None,
}
} else {
match express_as_power_i64(i64::wrapping_from(*self)) {
Some((base, exp)) => Some((Self::wrapping_from(base), exp)),
_ => None,
}
}
}
}
impl IsPower for i64 {
#[inline]
fn is_power(&self) -> bool {
is_power_i64(*self)
}
}
impl IsPower for i128 {
#[inline]
fn is_power(&self) -> bool {
is_power_i128(*self)
}
}
impl IsPower for isize {
fn is_power(&self) -> bool {
if USIZE_IS_U32 {
is_power_i32(i32::wrapping_from(*self))
} else {
is_power_i64(i64::wrapping_from(*self))
}
}
}
macro_rules! impl_signed_32 {
($t: ident) => {
impl ExpressAsPower for $t {
fn express_as_power(&self) -> Option<($t, u64)> {
match express_as_power_i32(i32::from(*self)) {
Some((base, exp)) => Some(($t::exact_from(base), exp)),
_ => None,
}
}
}
impl IsPower for $t {
#[inline]
fn is_power(&self) -> bool {
is_power_i32(i32::from(*self))
}
}
};
}
impl_signed_32!(i8);
impl_signed_32!(i16);
impl_signed_32!(i32);