use std::{convert::{TryInto, TryFrom}, ops::*, cmp::*};
use super::{complex::ComplexNumber, constants::{E, EULERMASCHERONI}};
use crate::eval_postfix;
use super::constants::{SQRT5, GOLDENRATIO};
pub mod avg_impl;
pub mod avg_macros;
pub trait Averages<T> {
type Output;
#[must_use]
fn arithmetic_mean(&self) -> Self::Output;
#[must_use]
fn harmonic_mean(&self) -> Self::Output;
#[must_use]
fn median(&self) -> Self::Output;
#[must_use]
fn mode(&self) -> T;
#[must_use]
fn mid_range(&self) -> Self::Output;
}
pub trait NumDigits {
#[must_use = "This returns the result of the operation, without modifying the original."]
fn cross_sum(&self) -> Self;
#[must_use]
fn digits(&self) -> Vec<u8>;
}
pub trait NumTools<T> {
#[must_use]
fn is_in_range(&self, start: Self, end: Self) -> bool;
#[must_use]
fn is_in_range_exclusive(&self, start: Self, end: Self) -> bool;
#[must_use = "This returns the result of the operation, without modifying the original."]
fn map_to(&self, start1: T, end1: T, start2: T, end2: T) -> T;
fn inc(&mut self);
fn inc_by(&mut self, n: Self);
fn dec(&mut self);
fn dec_by(&mut self, n: Self);
#[must_use = "This returns the result of the operation, without modifying the original."]
fn square(&self) -> Self;
#[must_use = "This returns the result of the operation, without modifying the original."]
fn cube(&self) -> Self;
#[must_use = "This returns the result of the operation, without modifying the original."]
fn recip(&self) -> Self;
#[must_use = "This returns the result of the operation, without modifying the original."]
fn pow(&self, power: usize) -> Self;
#[must_use]
fn is_negative(&self) -> bool;
}
impl<T: PartialOrd +
Sub<Output = T> +
Add<Output = T> +
Div<Output = T> +
Mul<Output = T> +
From<u8> +
Copy +
SubAssign +
AddAssign +
MulAssign> NumTools<T> for T {
#[inline]
fn is_in_range(&self, start: Self, end: Self) -> bool {
self >= &start &&
self <= &end
}
#[inline]
fn is_in_range_exclusive(&self, start: Self, end: Self) -> bool {
self > &start &&
self < &end
}
#[inline]
fn map_to(&self, start1: T, end1: T, start2: T, end2: T) -> T {
eval_postfix!(start2 end2 start2 - + (*self) start1 - end1 / start1 - *)
}
#[inline]
fn inc(&mut self) {
*self += 1u8.into();
}
#[inline]
fn inc_by(&mut self, n: Self) {
*self += n;
}
#[inline]
fn dec(&mut self) {
*self -= 1u8.into();
}
#[inline]
fn dec_by(&mut self, n: Self) {
*self -= n;
}
#[inline]
fn square(&self) -> Self {
*self * *self
}
#[inline]
fn cube(&self) -> Self {
*self * *self * *self
}
#[inline]
fn recip(&self) -> Self {
Self::from(1u8) / *self
}
#[inline]
fn pow(&self, power: usize) -> Self {
let self_is_zero = self == &0u8.into();
let power_is_zero = power == 0;
if self_is_zero && !power_is_zero
{ return 0u8.into(); }
if !self_is_zero && power_is_zero
{ return 1u8.into(); }
if self_is_zero && power_is_zero
{ panic!("0^0 is undefined."); }
let mut res = *self;
for _ in 2..(power + 1) {
res *= *self;
}
res
}
#[inline]
fn is_negative(&self) -> bool {
*self < T::from(0)
}
}
impl<'a, T: PartialEq +
DivAssign + PartialOrd +
Rem<Output = T> + Copy +
AddAssign +
Div<Output = T> +
Sub<Output = T> +
Add<Output = T> +
Mul<Output = T> +
AddAssign +
SubAssign +
MulAssign>
NumDigits
for T
where
u8: TryFrom<T>,
T: From<u8> {
fn cross_sum(&self) -> Self {
let d: Vec<u8> = self.digits();
let mut res: Self = 0.into();
for i in d {
res.inc_by(i.into());
}
res
}
fn digits(&self) -> Vec<u8> {
if self == &0u8.into() { return vec![0]; }
let mut v: Self = *self;
let mut digits: Vec<u8> = Vec::with_capacity(39);
while v > 0.into() {
let n: u8 = unsafe { (v % 10.into()).try_into().unwrap_unchecked() };
if n == 255
{ panic!("Oops! Something went wrong. please contact the developers using the error code 0x00001.")}
v /= 10.into();
digits.push(n);
}
digits
}
}
#[must_use = "This returns the result of the operation, without modifying the original."]
#[inline]
pub fn nth_root(degree: f64, radicand: f64) -> f64 {
radicand.powf(degree.recip())
}
#[must_use]
pub fn nth_fibonacci(n: u128) -> u128 {
if n > 186
{ panic!("Error: The 187th Fibonacci number and all above are not allowed, as they would cause a overflow in the u128 type."); }
if n < 76 {
return ( GOLDENRATIO.powi(n as i32) / SQRT5 ).round() as u128;
}
let mut x: u128;
let mut y: u128 = 1304969544928657;
let mut z: u128 = 2111485077978050;
let mut i: u128 = 75;
while i < n {
x = y;
y = z;
z = x + y;
i.inc();
}
z
}
#[must_use]
#[inline]
pub fn delta<T: Sub<Output = T> +
PartialOrd>(a: T, b: T) -> T {
match a > b {
true => { return a - b; }
false => { return b - a; }
}
}
#[inline]
pub fn better_be_even<T: From<bool> +
BitAnd<Output = T> +
PartialEq +
std::fmt::Display +
Copy>(x: T) {
if x & true.into() != false.into()
{ core::panic!("Oops! {} was not even.", x); }
}
#[inline]
#[must_use]
pub fn sqrt_f64(x: f64) -> ComplexNumber<f64> {
if x < 0.0
{ return ComplexNumber { real: 0.0, complex: (-x).sqrt() }; }
ComplexNumber { real: x.sqrt(), complex: 0.0 }
}
#[inline]
#[must_use]
pub fn sqrt_f32(x: f32) -> ComplexNumber<f32> {
if x < 0.0
{ return ComplexNumber { real: 0.0, complex: (-x).sqrt() }; }
ComplexNumber { real: x.sqrt(), complex: 0.0 }
}
pub fn euler_gamma<T: Into<f64>>(z: T, precision: f64) -> f64 {
let _z: f64 = z.into();
let pre: f64 = E.powf(-_z * EULERMASCHERONI) / _z;
let mut term_inf: f64 = E.powf(_z) /
(1.0 + _z);
let mut res: f64 = 1.0;
let mut n: f64 = 1.0;
let mut zdivn: f64;
if delta(term_inf, 1.0) < precision
{ return res; }
loop {
res *= term_inf;
if delta(term_inf, 1.0) < precision
{ break; }
n.inc();
zdivn = _z / n;
term_inf = E.powf(zdivn) /
(1.0 + zdivn);
}
pre * res
}
#[must_use]
pub fn gcd<T: From<u8> +
PartialEq +
PartialOrd +
Shl<Output = T> +
NumTools<T> +
Copy +
ShrAssign>(a: T, b: T) -> T
where
i128: From<T> {
let mut _a = a;
let mut _b = b;
if _b == 0.into()
{ return _a; }
if _a == 0.into()
{ return _b; }
let a_two_factor: u8 =
unsafe { i128::from(_a).trailing_zeros().try_into().unwrap_unchecked() };
let b_two_factor: u8 =
unsafe { i128::from(_b).trailing_zeros().try_into().unwrap_unchecked() };
let min_two_factor: u8 = std::cmp::min(a_two_factor, b_two_factor);
_a >>= a_two_factor.into();
_b >>= b_two_factor.into();
loop {
if _b > _a
{ std::mem::swap(&mut _b, &mut _a); }
_a.dec_by(_b);
if _a == 0.into()
{ return _b << min_two_factor.into(); }
_a >>= unsafe { u8::try_from(i128::from(_a).trailing_zeros()).unwrap_unchecked() }.into();
}
}
pub const fn factorial(n: u8) -> u128 {
let mut x = n as u128;
let mut _res = 1;
while x > 1 {
_res *= x;
x -= 1;
}
_res
}
pub const fn div_factorials(x: usize, y: usize) -> usize {
let k = x - y;
let mut _res = 1;
let mut i = 0;
while i != k {
_res *= x - i;
i += 1;
}
_res
}
pub fn round_to_n_mult<T: Div<Output = T> +
Mul<Output = T> +
Sub<Output = T> +
Add<Output = T> +
PartialOrd +
From<bool> +
Copy>(x: T, n: T) -> T {
let x_over_n = x / n;
let f1 = (x + true.into()) / n * n;
match delta(x_over_n, x) <= delta(x_over_n, f1) {
true => f1,
false => x
}
}