use num_bigint::BigUint;
#[cfg(feature = "std")] use rayon::prelude::*;
pub trait Num {
fn as_bool(&self) -> bool;
fn count(self) -> u32;
fn has_digit(self, k: Self) -> bool;
#[must_use]
fn rev(self) -> Self;
#[must_use]
fn sum(self) -> Self;
fn factorial(self) -> BigUint;
}
macro_rules! impl_num_signed {
($($type:ty)*) => {
$(impl Num for $type {
#[inline]
fn as_bool(&self) -> bool {
*self != 0
}
fn sum(self) -> Self {
let mut num = self.abs();
let mut sum = 0;
while num.as_bool() {
sum += num % 10;
num /= 10;
}
sum
}
#[inline]
fn count(self) -> u32 {
(self.abs().ilog10() + 1)
}
fn rev(self) -> Self {
let is_neg = self < 0;
let mut num = self.abs();
let mut rev = 0;
while num.as_bool() {
rev *= 10;
rev += num % 10;
num /= 10;
}
if is_neg {
rev *= -1;
}
rev
}
fn has_digit(self, digit: Self) -> bool {
let mut num = self.abs();
while num.as_bool() {
if num % 10 == digit {
return true;
}
num /= 10;
}
false
}
fn factorial(self) -> BigUint {
assert!(
self >= 0,
"Factorial can't be calculated for negative numbers at the moment"
);
let num = self.unsigned_abs();
match num {
0 | 1 => BigUint::from(1u8),
_ => {
cfg_select! {
feature = "std" => (2..=num).into_par_iter().map(BigUint::from).product(),
_ => (2..=num).map(BigUint::from).product(),
}
},
}
}
})*
}
}
macro_rules! impl_num_unsigned {
($($type:ty)*) => {
$(impl Num for $type {
#[inline]
fn as_bool(&self) -> bool {
*self != 0
}
fn sum(self) -> Self {
let mut num = self;
let mut sum = 0;
while num.as_bool() {
sum += num % 10;
num /= 10;
}
sum
}
#[inline]
fn count(self) -> u32 {
(self.ilog10() + 1)
}
fn rev(self) -> Self {
let mut num = self;
let mut rev = 0;
while num.as_bool() {
rev *= 10;
rev += num % 10;
num /= 10;
}
rev
}
fn has_digit(self, digit: Self) -> bool {
let mut num = self;
while num.as_bool() {
if num % 10 == digit {
return true;
}
num /= 10;
}
false
}
fn factorial(self) -> BigUint {
match self {
0 | 1 => BigUint::from(1u8),
_ => {
cfg_select! {
feature = "std" => (2..=self).into_par_iter().map(BigUint::from).product(),
_ => (2..=self).map(BigUint::from).product(),
}
},
}
}
})*
}
}
impl_num_signed!(i8 i16 i32 i64 i128 isize);
impl_num_unsigned!(u8 u16 u32 u64 u128 usize);