use core::ops::Shr;
use core::convert::TryInto;
use sp_arithmetic::{FixedI128, FixedI64, FixedU128, FixedU64};
use sp_runtime::{
FixedPointNumber,
traits::Bounded
};
pub trait FixedForInteger {
type FixedPoint: FixedPointNumber;
}
macro_rules! int_best_fixed {
($($t:ty => $fixed:ty),* $(,)?) => {
$(
impl FixedForInteger for $t {
type FixedPoint = $fixed;
}
)*
};
}
int_best_fixed! {
u8 => FixedU64,
u16 => FixedU64,
u32 => FixedU64,
u64 => FixedU128,
u128 => FixedU128,
usize => FixedU128,
i8 => FixedI64,
i16 => FixedI64,
i32 => FixedI64,
i64 => FixedI128,
i128 => FixedI128,
isize => FixedI128,
}
pub trait IntegerToFixed: Sized + FixedForInteger {
fn to_fixed(&self) -> <Self as FixedForInteger>::FixedPoint;
fn from_fixed(f: &<Self as FixedForInteger>::FixedPoint) -> Self;
}
macro_rules! impl_fixed_convert_unsigned {
($($t:ty),* => $fixed:ty) => {
$(
impl IntegerToFixed for $t {
fn to_fixed(&self) -> <$t as FixedForInteger>::FixedPoint {
<$fixed>::saturating_from_integer(*self as $t)
}
fn from_fixed(f: &<$t as FixedForInteger>::FixedPoint) -> Self {
let inner = f.into_inner().saturating_div(<$fixed>::DIV);
if inner > <$t>::MAX as _ {
<$t>::MAX
} else {
inner as $t
}
}
}
)*
};
}
macro_rules! impl_fixed_convert_signed {
($($t:ty),* => $fixed:ty) => {
$(
impl IntegerToFixed for $t {
fn to_fixed(&self) -> <$t as FixedForInteger>::FixedPoint {
<$fixed>::saturating_from_integer(*self as $t)
}
fn from_fixed(f: &<$t as FixedForInteger>::FixedPoint) -> Self {
let inner = f.into_inner().saturating_div(<$fixed>::DIV);
if inner > <$t>::MAX as _ {
<$t>::MAX
}
else if inner < <$t>::MIN as _ {
<$t>::MIN
}
else {
inner as $t
}
}
}
)*
};
}
impl_fixed_convert_unsigned!(u8, u16, u32 => FixedU64);
impl_fixed_convert_unsigned!(u64, u128, usize => FixedU128);
impl_fixed_convert_signed!(i8, i16, i32 => FixedI64);
impl_fixed_convert_signed!(i64, i128, isize => FixedI128);
pub trait FixedSignedCast : FixedPointNumber {
type Signed: FixedPointNumber;
fn saturating<F>(x: Self, f: F) -> Self where F: FnOnce(Self::Signed)->Self::Signed;
fn checked<F>(x: Self, f: F) -> Option<Self> where F: FnOnce(Option<Self::Signed>)->Self::Signed;
fn checked_into(x: Self) -> Option<Self::Signed>;
fn saturated_into(x: Self) -> Self::Signed;
fn checked_from(x: Self::Signed) -> Option<Self>;
fn saturated_from(x: Self::Signed) -> Self;
}
impl FixedSignedCast for FixedI64 {
type Signed = FixedI64;
fn saturating<F>(x: Self, f: F) -> Self
where
F: FnOnce(Self::Signed) -> Self::Signed,
{
f(x)
}
fn checked<F>(x: Self, f: F) -> Option<Self>
where
F: FnOnce(Option<Self::Signed>) -> Self::Signed,
{
let result = f(Some(x));
if result == Self::min_value() || result == Self::max_value() {
None
} else {
Some(result)
}
}
fn checked_into(x: Self) -> Option<Self::Signed> {
Some(x)
}
fn saturated_into(x: Self) -> Self::Signed {
x
}
fn checked_from(x: Self::Signed) -> Option<Self> {
Some(x)
}
fn saturated_from(x: Self::Signed) -> Self {
x
}
}
impl FixedSignedCast for FixedI128 {
type Signed = FixedI128;
fn saturating<F>(x: Self, f: F) -> Self
where
F: FnOnce(Self::Signed) -> Self::Signed,
{
f(x)
}
fn checked<F>(x: Self, f: F) -> Option<Self>
where
F: FnOnce(Option<Self::Signed>) -> Self::Signed,
{
let result = f(Some(x));
if result == Self::min_value() || result == Self::max_value() {
None
} else {
Some(result)
}
}
fn checked_into(x: Self) -> Option<Self::Signed> {
Some(x)
}
fn saturated_into(x: Self) -> Self::Signed {
x
}
fn checked_from(x: Self::Signed) -> Option<Self> {
Some(x)
}
fn saturated_from(x: Self::Signed) -> Self {
x
}
}
impl FixedSignedCast for FixedU64 {
type Signed = FixedI128;
fn saturating<F>(x: Self, f: F) -> Self
where
F: FnOnce(Self::Signed) -> Self::Signed,
{
let signed = FixedI128::from_inner(x.into_inner() as i128);
let result = f(signed);
Self::saturated_from(result)
}
fn checked<F>(x: Self, f: F) -> Option<Self>
where
F: FnOnce(Option<Self::Signed>) -> Self::Signed,
{
let signed = FixedI128::from_inner(x.into_inner() as i128);
let result = f(Some(signed));
Self::checked_from(result)
}
fn checked_into(x: Self) -> Option<Self::Signed> {
Some(FixedI128::from_inner(x.into_inner() as i128))
}
fn saturated_into(x: Self) -> Self::Signed {
FixedI128::from_inner(x.into_inner() as i128)
}
fn checked_from(x: Self::Signed) -> Option<Self> {
let inner = x.into_inner();
match inner < 0 || inner > u64::MAX as i128 {
true => None,
false => Some(FixedU64::from_inner(inner as u64)),
}
}
fn saturated_from(x: Self::Signed) -> Self {
let inner = x.into_inner();
let clamped = match inner {
b if b < 0 => 0,
b if b > u64::MAX as i128 => u64::MAX,
b => b as u64,
};
FixedU64::from_inner(clamped)
}
}
impl FixedSignedCast for FixedU128 {
type Signed = FixedI128;
fn saturating<F>(x: Self, f: F) -> Self
where
F: FnOnce(Self::Signed) -> Self::Signed,
{
let signed = Self::saturated_into(x);
let result = f(signed);
Self::saturated_from(result)
}
fn checked<F>(x: Self, f: F) -> Option<Self>
where
F: FnOnce(Option<Self::Signed>) -> Self::Signed,
{
let signed = Self::checked_into(x);
let result = f(signed);
Self::checked_from(result)
}
fn checked_into(x: Self) -> Option<Self::Signed> {
let inner = x.into_inner();
match inner > i128::MAX as u128 {
true => None,
false => Some(FixedI128::from_inner(inner as i128)),
}
}
fn saturated_into(x: Self) -> Self::Signed {
let inner = x.into_inner();
match inner > i128::MAX as u128 {
true => FixedI128::from_inner(i128::MAX),
false => FixedI128::from_inner(inner as i128),
}
}
fn checked_from(x: Self::Signed) -> Option<Self> {
let inner = x.into_inner();
match inner < 0 {
true => None,
false => Some(FixedU128::from_inner(inner as u128))
}
}
fn saturated_from(x: Self::Signed) -> Self {
let inner = x.into_inner();
let clamped = match inner < 0 {
true => 0,
false => inner as u128
};
FixedU128::from_inner(clamped)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Complex<T> {
pub real: T,
pub imgn: T,
}
impl<T> Complex<T> {
fn new(real: T, imgn: T) -> Self {
Self { real, imgn }
}
}
pub trait FixedPointInfo {
const INNER_BITS: u32;
const DECIMAL_PLACES: u32;
}
impl FixedPointInfo for FixedU64 {
const INNER_BITS: u32 = 64; const DECIMAL_PLACES: u32 = 9;
}
impl FixedPointInfo for FixedI64 {
const INNER_BITS: u32 = 64; const DECIMAL_PLACES: u32 = 9;
}
impl FixedPointInfo for FixedU128 {
const INNER_BITS: u32 = 128; const DECIMAL_PLACES: u32 = 18;
}
impl FixedPointInfo for FixedI128 {
const INNER_BITS: u32 = 128; const DECIMAL_PLACES: u32 = 18;
}
fn ulp<F: FixedPointNumber>() -> F
where
F::Inner: From<u8>,
{
F::from_inner(F::Inner::from(1u8))
}
const MAX_ITERATIONS: u32 = 50;
fn to_u32_floor<T>(x: &T) -> u32
where
T: FixedPointNumber + Copy + FixedPointInfo,
T::Inner: Copy + PartialOrd + TryInto<i128>,
{
let inner = x.into_inner();
let inner_i128: i128 = match inner.try_into() {
Ok(val) => val,
Err(_) => return u32::MAX,
};
let div: i128 = match T::DIV.try_into() {
Ok(val) => val,
Err(_) => return 0,
};
let int_part = inner_i128 / div;
if int_part < 0 {
0
} else if int_part > u32::MAX as i128 {
u32::MAX
} else {
int_part as u32
}
}
fn fixed_to_i128<T>(x: &T) -> Option<i128>
where
T: FixedPointNumber,
T::Inner: TryInto<i128> + Copy,
{
let inner: i128 = x.into_inner().try_into().ok()?;
let div: i128 = T::DIV.try_into().ok()?;
if inner % div == 0 {
Some(inner / div)
} else {
None
}
}
#[allow(dead_code)]
fn fixed_pi<T>() -> T
where
T: FixedPointNumber,
{
T::saturating_from_rational(355, 113)
}
#[allow(dead_code)]
fn dynamic_max_iterations<T>(x: &T) -> u32
where
T: FixedPointNumber + Copy + FixedPointInfo,
T::Inner: Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let abs_x = x.saturating_abs();
let int_part = to_u32_floor(&abs_x);
int_part
.saturating_mul(T::DECIMAL_PLACES)
.saturating_add(1)
}
fn fixed_sqrt_newton<F: FixedPointNumber>(x: &F) -> F
where
F::Inner: From<u8>,
{
let zero = F::zero();
if *x <= zero {
return zero;
}
let one = F::one();
let two = one.saturating_add(one);
let tol = ulp::<F>().saturating_add(ulp::<F>());
let mut guess = match x.cmp(&one) {
core::cmp::Ordering::Greater => {
x.saturating_add(one).checked_div(&two).unwrap_or(one)
}
core::cmp::Ordering::Equal => return one,
core::cmp::Ordering::Less => {
let quarter = F::saturating_from_rational(1, 4);
if *x > quarter { *x } else { quarter }
}
};
let mut prev_diff: Option<F> = None;
for _ in 0..MAX_ITERATIONS {
let div = match x.checked_div(&guess) {
Some(d) => d,
None => return guess,
};
let next = guess.saturating_add(div)
.checked_div(&two)
.unwrap_or(guess);
let diff = if next > guess {
next.saturating_sub(guess)
} else {
guess.saturating_sub(next)
};
if diff <= tol {
return next;
}
if let Some(pd) = prev_diff {
if diff >= pd {
return next;
}
}
prev_diff = Some(diff);
guess = next;
}
guess
}
fn range_reduce_sqrt<T>(mut y: T) -> (T, u32)
where
T: FixedPointNumber + Copy + PartialOrd,
T::Inner: From<u8> + Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let one = T::one();
let half = T::saturating_from_rational(1, 2);
let mut k: u32 = 0;
for _ in 0..MAX_ITERATIONS {
let diff = if y > one {
y.saturating_sub(one)
} else {
one.saturating_sub(y)
};
if diff <= half {
break;
}
let ny = fixed_sqrt_newton::<T>(&y);
if ny == y {
break;
}
if ny == T::zero() {
break;
}
y = ny;
k += 1;
}
(y, k)
}
fn ln_near_one<T>(y: T) -> T
where
T: FixedPointNumber + Copy + PartialOrd + FixedPointInfo,
T::Inner: From<u8> + Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let one = T::one();
let two = one.saturating_add(one);
let eps = ulp::<T>();
let num = y.saturating_sub(one); let denom = y.saturating_add(one); let t = num.checked_div(&denom).unwrap_or(T::zero());
let t_sq = t.checked_mul(&t).unwrap_or(T::zero());
let mut sum = T::zero();
let mut power = t;
for i in 0u32..MAX_ITERATIONS {
let denom_fp = T::saturating_from_integer(2 * i + 1);
let term = power.checked_div(&denom_fp).unwrap_or(T::zero());
if term.saturating_abs() <= eps {
break;
}
let new_sum = sum.saturating_add(term);
if new_sum == sum {
break;
}
sum = new_sum;
power = power.checked_mul(&t_sq).unwrap_or(T::zero());
}
sum.saturating_mul(two)
}
fn fixed_powi<T>(x: T, n: i128) -> Option<T>
where
T: FixedPointNumber + Copy,
{
let one = T::one();
let zero = T::zero();
if n == 0 {
return Some(one);
}
if n < 0 {
if x == zero {
return None;
}
let pos = fixed_powi_positive(x, n.unsigned_abs());
return one.checked_div(&pos);
}
Some(fixed_powi_positive(x, n as u128))
}
fn fixed_powi_positive<T>(x: T, mut n: u128) -> T
where
T: FixedPointNumber + Copy,
{
let one = T::one();
let mut result = one;
let mut base = x;
while n > 0 {
if (n & 1) == 1 {
result = result.saturating_mul(base);
}
n >>= 1;
if n > 0 {
base = base.saturating_mul(base);
}
}
result
}
fn fixed_sqrt<F: FixedPointNumber>(x: &F) -> Option<F>
where
F::Inner: From<u8>,
{
let zero = F::zero();
let one = F::one();
if *x < zero {
return None;
}
if *x == zero {
return Some(zero);
}
if *x == one {
return Some(one);
}
Some(fixed_sqrt_newton::<F>(x))
}
fn complex_sqrt<F: FixedPointNumber>(x: &F) -> Option<Complex<F>>
where
F::Inner: From<u8>,
{
let zero = F::zero();
if *x == zero {
return Some(Complex::new(zero, zero));
}
if *x < zero {
let mag = x.saturating_abs();
let imgn = fixed_sqrt_newton::<F>(&mag);
return Some(Complex::new(zero, imgn));
}
let real = fixed_sqrt_newton::<F>(x);
Some(Complex::new(real, zero))
}
fn fixed_exp<T>(x: &T) -> Option<T>
where
T: FixedPointNumber + Copy + PartialOrd + FixedPointInfo,
T::Inner: From<u8> + Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let zero = T::zero();
let one = T::one();
if *x == zero {
return Some(one);
}
let neg_threshold = T::saturating_from_integer(
-((T::DECIMAL_PLACES as i32).saturating_mul(10))
);
if *x < neg_threshold {
return Some(zero);
}
let n_i128: i128 = {
let inner: i128 = x.into_inner().try_into().ok()?;
let div: i128 = T::DIV.try_into().ok()?;
inner / div
};
let n = n_i128.clamp(i32::MIN as i128, i32::MAX as i128) as i32;
let n_fixed = T::saturating_from_integer(n);
let r = x.saturating_sub(n_fixed);
let epsilon = ulp::<T>();
let mut sum = one; let mut term = one;
for i in 1u32..=MAX_ITERATIONS {
let i_fixed = T::saturating_from_integer(i);
let next_term = term.checked_mul(&r)
.unwrap_or(zero)
.checked_div(&i_fixed)
.unwrap_or(zero);
if next_term.saturating_abs() <= epsilon {
break;
}
let new_sum = sum.saturating_add(next_term);
if new_sum == sum {
break;
}
sum = new_sum;
term = next_term;
}
if n == 0 {
return Some(sum);
}
let e = T::saturating_from_rational(
2_718_281_828_459_045_235u128,
1_000_000_000_000_000_000u128,
);
let exp_n = fixed_powi(e, n as i128)?;
if exp_n >= T::max_value() {
return None;
}
sum.checked_mul(&exp_n)
}
fn fixed_ln<T>(x: &T) -> Option<T>
where
T: FixedPointNumber + Copy + PartialOrd + FixedPointInfo ,
T::Inner: From<u8> + Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let zero = T::zero();
let one = T::one();
if *x <= zero {
return None;
}
if *x == one {
return Some(zero);
}
let is_unsigned = zero.saturating_sub(one) == zero;
if is_unsigned && *x < one {
return None;
}
let (y_reduced, k) = range_reduce_sqrt(*x);
let mut ln_val = ln_near_one(y_reduced);
if k > 31 {
return None;
}
if k > 0 {
let scale = T::saturating_from_integer(1u32 << k);
ln_val = ln_val.saturating_mul(scale);
}
Some(ln_val)
}
fn fixed_pow<T>(x: &T, p: &T) -> Option<T>
where
T: FixedPointNumber + Copy + PartialOrd + FixedPointInfo,
T::Inner: From<u8> + Shr<u32, Output = T::Inner> + TryInto<i128> + Copy,
{
let zero = T::zero();
let one = T::one();
if *x == zero && *p <= zero {
return None;
}
if *x == zero {
return Some(zero);
}
let int_exp = fixed_to_i128(p);
if *x < zero && int_exp.is_none() {
return None;
}
if *p == zero {
return Some(one);
}
if *x == one {
return Some(one);
}
if let Some(n) = int_exp {
return fixed_powi(*x, n);
}
let ln_x = fixed_ln(x)?;
let exponent = p.saturating_mul(ln_x);
fixed_exp(&exponent)
}
pub trait FixedOp
where
Self: Sized,
{
fn fixed_sqrt(f: &Self) -> Option<Self>;
fn fixed_pow(f: &Self, p: &Self) -> Option<Self>;
fn fixed_exp(f: &Self) -> Option<Self>;
fn fixed_ln(f: &Self) -> Option<Self>;
}
pub trait FixedComplexOp
where
Self: Sized,
{
fn complex_sqrt(f: &Self) -> Option<Complex<Self>>;
}
impl FixedOp for FixedU64 {
fn fixed_sqrt(f: &Self) -> Option<Self> {
fixed_sqrt(f)
}
fn fixed_pow(f: &Self, p: &Self) -> Option<Self> {
fixed_pow(f, p)
}
fn fixed_exp(f: &Self) -> Option<Self> {
fixed_exp(f)
}
fn fixed_ln(f: &Self) -> Option<Self> {
fixed_ln(f)
}
}
impl FixedOp for FixedU128 {
fn fixed_sqrt(f: &Self) -> Option<Self> {
fixed_sqrt(f)
}
fn fixed_pow(f: &Self, p: &Self) -> Option<Self> {
fixed_pow(f, p)
}
fn fixed_exp(f: &Self) -> Option<Self> {
fixed_exp(f)
}
fn fixed_ln(f: &Self) -> Option<Self> {
fixed_ln(f)
}
}
impl FixedOp for FixedI64 {
fn fixed_sqrt(f: &Self) -> Option<Self> {
fixed_sqrt(f)
}
fn fixed_pow(f: &Self, p: &Self) -> Option<Self> {
fixed_pow(f, p)
}
fn fixed_exp(f: &Self) -> Option<Self> {
fixed_exp(f)
}
fn fixed_ln(f: &Self) -> Option<Self> {
fixed_ln(f)
}
}
impl FixedOp for FixedI128 {
fn fixed_sqrt(f: &Self) -> Option<Self> {
fixed_sqrt(f)
}
fn fixed_pow(f: &Self, p: &Self) -> Option<Self> {
fixed_pow(f, p)
}
fn fixed_exp(f: &Self) -> Option<Self> {
fixed_exp(f)
}
fn fixed_ln(f: &Self) -> Option<Self> {
fixed_ln(f)
}
}
impl FixedComplexOp for FixedU64 {
fn complex_sqrt(f: &Self) -> Option<Complex<Self>> {
complex_sqrt(f)
}
}
impl FixedComplexOp for FixedI64 {
fn complex_sqrt(f: &Self) -> Option<Complex<Self>> {
complex_sqrt(f)
}
}
impl FixedComplexOp for FixedU128 {
fn complex_sqrt(f: &Self) -> Option<Complex<Self>> {
complex_sqrt(f)
}
}
impl FixedComplexOp for FixedI128 {
fn complex_sqrt(f: &Self) -> Option<Complex<Self>> {
complex_sqrt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::traits::{Bounded, One, Saturating, Zero};
#[test]
fn fixed_sqrt_perfect_cases() {
let x: FixedU64 = 4.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(2);
assert_eq!(result, expected);
let x: FixedU64 = 36.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(6);
assert_eq!(result, expected);
let x: FixedU64 = 81.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(9);
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(1);
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_negative_perfect_cases() {
let x: FixedI64 = (-1).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-16).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-9).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-100).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-4).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
}
#[test]
fn fixed_sqrt_large_numbers() {
let x: FixedU64 = 10000.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(100);
assert_eq!(result, expected);
let x: FixedU64 = 1000000.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_integer(1000);
assert_eq!(result, expected);
let x: FixedU64 = (u32::MAX as u64).into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::from_inner(65535999992370);
assert_eq!(result, expected);
let x: FixedU64 = (u64::MAX).into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::from_inner(135818791312945);
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_non_perfect_cases() {
let x: FixedU64 = 2.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::from_inner(1414213562);
assert_eq!(result, expected);
let x: FixedU64 = 5.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::from_inner(2236067977);
assert_eq!(result, expected);
let x: FixedU64 = 10.into();
let result = fixed_sqrt(&x).unwrap();
let expected: FixedU64 = FixedU64::from_inner(3162277660);
assert_eq!(result, expected);
let x: FixedU64 = 125.into();
let result = fixed_sqrt(&x).unwrap();
let expected: FixedU64 = FixedU64::from_inner(11180339887);
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_negative_non_perfect_squares() {
let x: FixedI64 = (-2).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-35).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x: FixedI64 = (-50).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
}
#[test]
fn fixed_sqrt_fractional_cases() {
let x = FixedU64::saturating_from_rational(1, 4);
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_rational(1, 2);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 100);
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::saturating_from_rational(1, 10);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 2);
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::from_inner(707106781);
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_edge_cases() {
let x: FixedU64 = 0.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::zero();
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedU64::one();
assert_eq!(result, expected);
let x: FixedI64 = (i64::MIN).into();
let result = fixed_sqrt(&x);
assert!(result.is_none());
let x = FixedI64::max_value();
let result = fixed_sqrt(&x).unwrap();
let expected = FixedI64::from_inner(96038388349944);
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_perfect_cases() {
let x: FixedU64 = 4.into();
let result = complex_sqrt(&x).unwrap();
let expected: Complex<FixedU64> = Complex {
real: 2.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 36.into();
let result = complex_sqrt(&x).unwrap();
let expected: Complex<FixedU64> = Complex {
real: 6.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 81.into();
let result = complex_sqrt(&x).unwrap();
let expected: Complex<FixedU64> = Complex {
real: 9.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 1.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_negative_perfect_cases() {
let x: FixedI64 = (-1).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 1.into(),
};
assert_eq!(result, expected);
let x: FixedI64 = (-16).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 4.into(),
};
assert_eq!(result, expected);
let x: FixedI64 = (-9).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 3.into(),
};
assert_eq!(result, expected);
let x: FixedI64 = (-100).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 10.into(),
};
assert_eq!(result, expected);
let x: FixedI64 = (-4).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 2.into(),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_large_numbers() {
let x: FixedU64 = 10000.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 100.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 1000000.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 1000.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = (u32::MAX as u64).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::from_inner(65535999992370),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = (u64::MAX).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::from_inner(135818791312945),
imgn: 0.into(),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_non_perfect_cases() {
let x: FixedU64 = 2.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::from_inner(1414213562),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 5.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::from_inner(2236067977),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 10.into();
let result = complex_sqrt(&x).unwrap();
let expected: Complex<FixedU64> = Complex {
real: FixedU64::from_inner(3162277660),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 125.into();
let result = complex_sqrt(&x).unwrap();
let expected: Complex<FixedU64> = Complex {
real: FixedU64::from_inner(11180339887),
imgn: 0.into(),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_negative_non_perfect_squares() {
let x: FixedI64 = (-2).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: FixedI64::from_inner(1414213562),
};
assert_eq!(result, expected);
let x: FixedI64 = (-35).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: FixedI64::from_inner(5916079783),
};
assert_eq!(result, expected);
let x: FixedI64 = (-50).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: FixedI64::from_inner(7071067811),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_fractional_cases() {
let x = FixedU64::saturating_from_rational(1, 4);
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::saturating_from_rational(1, 2),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 100);
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::saturating_from_rational(1, 10),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 2);
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedU64::from_inner(707106781),
imgn: 0.into(),
};
assert_eq!(result, expected);
}
#[test]
fn complex_sqrt_edge_cases() {
let x: FixedU64 = 0.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 1.into(),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x = FixedI64::max_value();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: FixedI64::from_inner(96038388349944),
imgn: 0.into(),
};
assert_eq!(result, expected);
let x: FixedI64 = (i64::MIN).into();
let result = complex_sqrt(&x).unwrap();
let expected = Complex {
real: 0.into(),
imgn: FixedI64::from_inner(96038388349944),
};
assert_eq!(result, expected);
}
#[test]
fn fixed_exp_normal_cases() {
let x: FixedU64 = 0.into();
let result = fixed_exp(&x).unwrap();
let expected = 1.into();
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(2718281828);
assert_eq!(result, expected);
let x: FixedU64 = 2.into();
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(7389056096);
assert_eq!(result, expected);
let x: FixedU64 = 3.into();
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(20085536911);
assert_eq!(result, expected);
let x: FixedU64 = 5.into();
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(148413158957);
assert_eq!(result, expected);
}
#[test]
fn fixed_exp_positive_fractional_edge_cases() {
let x = FixedU64::saturating_from_rational(1, 2);
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(1648721267);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 10);
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(1105170915);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 1000);
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(1001000500);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(5, 2);
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(12182493928);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(3, 2);
let result = fixed_exp(&x).unwrap();
let expected = FixedU64::from_inner(4481689059);
assert_eq!(result, expected);
}
#[test]
fn fixed_exp_negative_edge_cases() {
let x: FixedI64 = (-1).into();
let result = fixed_exp(&x).unwrap();
let expected = FixedI64::from_inner(367879441);
assert_eq!(result, expected);
let x: FixedI64 = (-2).into();
let result = fixed_exp(&x).unwrap();
let expected = FixedI64::from_inner(135335283);
assert_eq!(result, expected);
let x = FixedI64::saturating_from_rational(-1, 2);
let result = fixed_exp(&x).unwrap();
let expected = FixedI64::from_inner(606530659);
assert_eq!(result, expected);
let x: FixedI64 = (-15).into();
let result = fixed_exp(&x).unwrap();
let expected = FixedI64::from_inner(000000305);
assert_eq!(result, expected);
}
#[test]
fn fixed_exp_mathematical_constants() {
let ln2 = FixedU64::from_inner(693147181);
let result = fixed_exp(&ln2).unwrap();
let expected: FixedU64 = 2.into();
let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
let tolerance = FixedU64::from_inner(1_000_000); assert!(diff < tolerance);
let ln10 = FixedU64::from_inner(2302585093);
let result = fixed_exp(&ln10).unwrap();
let expected: FixedU64 = 10.into();
let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
}
#[test]
fn fixed_ln_at_one() {
let x: FixedU64 = 1.into();
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(0);
assert_eq!(result, expected);
}
#[test]
fn fixed_ln_at_zero() {
let x: FixedU64 = 0.into();
let result = fixed_ln(&x);
assert!(result.is_none());
}
#[test]
fn fixed_ln_positive_integers() {
let x: FixedU64 = 2.into();
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(693147172);
assert_eq!(result, expected);
let x: FixedU64 = 3.into();
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(1098612248);
assert_eq!(result, expected);
let x: FixedU64 = 10.into();
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(2302585040);
assert_eq!(result, expected);
let x: FixedU64 = 100.into();
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(4605170080);
assert_eq!(result, expected);
}
#[test]
fn fixed_ln_fractional_values() {
let x = FixedI64::saturating_from_rational(1, 2);
let result = fixed_ln(&x).unwrap();
let expected = FixedI64::from_inner(-693147174);
assert_eq!(result, expected);
let x = FixedI64::saturating_from_rational(1, 10);
let result = fixed_ln(&x).unwrap();
let expected = FixedI64::from_inner(-2302585064);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(3, 2);
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(405465100);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(5, 2);
let result = fixed_ln(&x).unwrap();
let expected = FixedU64::from_inner(916290712);
assert_eq!(result, expected);
let x = FixedU64::saturating_from_rational(1, 2);
let result = fixed_ln(&x);
assert!(result.is_none());
let x = FixedU64::saturating_from_rational(1, 10);
let result = fixed_ln(&x);
assert!(result.is_none());
}
#[test]
fn fixed_ln_negative_values() {
let x: FixedI64 = (-1).into();
let result = fixed_ln(&x);
assert!(result.is_none());
let x: FixedI64 = (-2).into();
let result = fixed_ln(&x);
assert!(result.is_none());
let x: FixedI64 = (-10).into();
let result = fixed_ln(&x);
assert!(result.is_none());
let x = FixedI64::saturating_from_rational(-1, 2);
let result = fixed_ln(&x);
assert!(result.is_none());
}
#[test]
fn fixed_ln_mathematical_constants() {
let e = FixedU64::from_inner(2718281828);
let result = fixed_ln(&e).unwrap();
let expected = FixedU64::from_inner(1000000000);
let tolerance = FixedU64::from_inner(1_000_000); let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
}
#[test]
fn fixed_ln_inverse_of_exp() {
let x: FixedU64 = 1.into();
let exp_x = fixed_exp(&x).unwrap();
let result = fixed_ln(&exp_x).unwrap();
let tolerance = FixedU64::from_inner(1_000_000); let diff = if result > x {
result.saturating_sub(x)
} else {
x.saturating_sub(result)
};
assert!(diff < tolerance);
let x: FixedU64 = 2.into();
let exp_x = fixed_exp(&x).unwrap();
let result = fixed_ln(&exp_x).unwrap();
let diff = if result > x {
result.saturating_sub(x)
} else {
x.saturating_sub(result)
};
assert!(diff < tolerance);
}
#[test]
fn fixed_ln_properties_verification() {
let x: FixedU64 = 6.into();
let ln_6 = fixed_ln(&x).unwrap();
let two: FixedU64 = 2.into();
let three: FixedU64 = 3.into();
let ln_2 = fixed_ln(&two).unwrap();
let ln_3 = fixed_ln(&three).unwrap();
let sum = ln_2.saturating_add(ln_3);
let tolerance = FixedU64::from_inner(1_000_000); let diff = if ln_6 > sum {
ln_6.saturating_sub(sum)
} else {
sum.saturating_sub(ln_6)
};
assert!(diff < tolerance);
}
#[test]
fn fixed_pow_edge_cases() {
let x: FixedU64 = 1.into();
let p: FixedU64 = 0.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 1.into();
assert_eq!(result, expected);
let x: FixedU64 = 0.into();
let p: FixedU64 = 1.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 0.into();
assert_eq!(result, expected);
let x: FixedU64 = 1.into();
let p: FixedU64 = 1.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 1.into();
assert_eq!(result, expected);
let x: FixedI64 = 0.into();
let p: FixedI64 = (-1).into();
let result = fixed_pow(&x, &p);
assert!(result.is_none());
}
#[test]
fn fixed_pow_normal_cases() {
let x: FixedU64 = 2.into();
let p: FixedU64 = 3.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 8.into();
assert_eq!(result, expected);
let x: FixedU64 = 4.into();
let p: FixedU64 = 5.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 1024.into();
assert_eq!(result, expected);
let x: FixedU64 = 8.into();
let p: FixedU64 = 6.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 262144.into();
assert_eq!(result, expected);
}
#[test]
fn fixed_pow_fractional_exponents() {
let tolerance: FixedU64 = FixedU64::from_inner(1_000_000);
let x: FixedU64 = 4.into();
let p = FixedU64::saturating_from_rational(1, 2);
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedU64 = 2.into();
let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
let x: FixedU64 = 9.into();
let p = FixedU64::saturating_from_rational(1, 4);
let result = fixed_pow(&x, &p).unwrap();
let expected = FixedU64::saturating_from_rational(1732051, 1_000_000); let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
let x: FixedU64 = 12.into();
let p = FixedU64::saturating_from_rational(35, 100); let result = fixed_pow(&x, &p).unwrap();
let expected = FixedU64::saturating_from_rational(2_386_876, 1_000_000);
let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
}
#[test]
fn fixed_pow_fractional_base_integer_exp() {
let tolerance = FixedU64::from_inner(1_000_000);
let x = FixedU64::saturating_from_rational(3, 2);
let p: FixedU64 = 2.into();
let result = fixed_pow(&x, &p).unwrap();
let expected = FixedU64::saturating_from_rational(9, 4);
let diff = if result > expected {
result.saturating_sub(expected)
} else {
expected.saturating_sub(result)
};
assert!(diff < tolerance);
let x = FixedU64::saturating_from_rational(7, 2); let p: FixedU64 = 4.into();
let result = fixed_pow(&x, &p).unwrap();
let expected = FixedU64::from_inner(150062500000);
assert_eq!(result, expected);
}
#[test]
fn fixed_pow_negative_base_integer_exp() {
let x: FixedI64 = (-2).into();
let p: FixedI64 = 3.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedI64 = (-8).into();
assert_eq!(result, expected);
let x: FixedI64 = (-6).into();
let p: FixedI64 = 5.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedI64 = (-7776).into();
assert_eq!(result, expected);
let x: FixedI64 = (-4).into();
let p: FixedI64 = 2.into();
let result = fixed_pow(&x, &p).unwrap();
let expected: FixedI64 = (16).into();
assert_eq!(result, expected);
}
#[test]
fn fixed_pow_negative_base_fractional_exp() {
let x: FixedI64 = (-4).into();
let p = FixedI64::saturating_from_rational(1, 2);
let result = fixed_pow(&x, &p);
assert!(result.is_none());
let x: FixedI64 = (-8).into();
let p = FixedI64::saturating_from_rational(1, 3);
let result = fixed_pow(&x, &p);
assert!(result.is_none())
}
#[test]
fn fixed_pow_large_integer_overflow_saturates() {
let x: FixedU64 = 2.into();
let p: FixedU64 = 128.into();
let result = fixed_pow(&x, &p).unwrap();
let expected = u64::MAX.into();
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_newton_standard_cases() {
let x: FixedU64 = (81).into();
let result = fixed_sqrt_newton(&x);
let expected = 9.into();
assert_eq!(result, expected);
let x: FixedU64 = (49).into();
let result = fixed_sqrt_newton(&x);
let expected = 7.into();
assert_eq!(result, expected);
let x: FixedU64 = 10.into();
let result = fixed_sqrt_newton(&x);
let expected: FixedU64 = FixedU64::from_inner(3162277660);
assert_eq!(result, expected);
let x: FixedU64 = 7.into();
let result = fixed_sqrt_newton(&x);
let expected: FixedU64 = FixedU64::from_inner(2645751311);
assert_eq!(result, expected);
}
#[test]
fn fixed_sqrt_newton_edge_cases() {
let x: FixedU64 = (0).into();
let result = fixed_sqrt_newton(&x);
let expected = 0.into();
assert_eq!(result, expected);
let x: FixedI64 = (-9).into();
let result = fixed_sqrt_newton(&x);
let expected = 0.into();
assert_eq!(result, expected);
}
#[test]
fn fixed_pi_value_check() {
let actual: FixedU64 = fixed_pi();
let expected = FixedU64::from_inner(3141592920);
assert_eq!(actual, expected);
}
#[test]
fn range_reduce_sqrt_already_in_range() {
let y: FixedU64 = 1.into();
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(reduced, y);
assert_eq!(k, 0);
let y = FixedU64::saturating_from_rational(3, 2);
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(reduced, y);
assert_eq!(k, 0);
let y = FixedU64::saturating_from_rational(1, 2);
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(reduced, y);
assert_eq!(k, 0);
let y = FixedU64::saturating_from_rational(3, 4);
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(reduced, y);
assert_eq!(k, 0);
}
#[test]
fn range_reduce_sqrt_needs_reduction_above_range() {
let half = FixedU64::saturating_from_rational(1, 2);
let one_half = FixedU64::saturating_from_rational(3, 2);
let y: FixedU64 = 4.into();
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(k, 2);
assert!(reduced >= half && reduced <= one_half);
let y: FixedU64 = 16.into();
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(k, 3); assert!(reduced >= half && reduced <= one_half);
let y: FixedU64 = 100.into();
let (reduced, k) = range_reduce_sqrt(y);
assert!(k > 0);
assert!(reduced >= half && reduced <= one_half);
}
#[test]
fn range_reduce_sqrt_needs_reduction_below_range() {
let half = FixedU64::saturating_from_rational(1, 2);
let one_half = FixedU64::saturating_from_rational(3, 2);
let y = FixedU64::saturating_from_rational(1, 4);
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(k, 1);
assert!(reduced >= half && reduced <= one_half);
let y = FixedU64::saturating_from_rational(1, 100);
let (reduced, k) = range_reduce_sqrt(y);
assert!(k > 0);
assert_eq!(k, 3);
assert!(reduced >= half && reduced <= one_half);
let y = FixedU64::saturating_from_rational(1, 10000);
let (reduced, k) = range_reduce_sqrt(y);
assert!(k > 0);
assert_eq!(k, 4);
assert!(reduced >= half && reduced <= one_half);
}
#[test]
fn range_reduce_sqrt_edge_cases() {
let y: FixedU64 = 0.into();
let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(reduced, y);
assert_eq!(k, 0);
let y = FixedU64::from_inner(1000000001); let (reduced, k) = range_reduce_sqrt(y);
assert_eq!(k, 0);
assert_eq!(reduced, y);
let y: FixedU64 = (u32::MAX as u64).into();
let (reduced, k) = range_reduce_sqrt(y);
assert!(k > 0);
let half = FixedU64::saturating_from_rational(1, 2);
let one_half = FixedU64::saturating_from_rational(3, 2);
assert!(reduced >= half && reduced <= one_half);
}
#[test]
fn ln_near_one_at_one() {
let y: FixedU64 = 1.into();
let result = ln_near_one(y);
let expected: FixedU64 = 0.into();
assert_eq!(result, expected);
}
#[test]
fn ln_near_one_slightly_above_one() {
let y = FixedU64::saturating_from_rational(11, 10);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(95310176);
assert_eq!(result, expected);
let y = FixedU64::saturating_from_rational(6, 5);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(182321552);
assert_eq!(result, expected);
let y = FixedU64::saturating_from_rational(3, 2);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(405465100);
assert_eq!(result, expected);
}
#[test]
fn ln_near_one_slightly_below_one() {
let y = FixedU64::saturating_from_rational(9, 10);
let _result = ln_near_one(y);
let y_signed = FixedI64::saturating_from_rational(9, 10);
let result_signed = ln_near_one(y_signed);
let expected = FixedI64::from_inner(-105360510);
assert_eq!(result_signed, expected);
let y = FixedI64::saturating_from_rational(4, 5);
let result = ln_near_one(y);
let expected = FixedI64::from_inner(-223143548);
assert_eq!(result, expected);
let y = FixedI64::saturating_from_rational(1, 2);
let result = ln_near_one(y);
let expected = FixedI64::from_inner(-693147174);
assert_eq!(result, expected);
}
#[test]
fn ln_near_one_very_close_to_one() {
let y = FixedU64::saturating_from_rational(101, 100);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(9950330);
assert_eq!(result, expected);
let y = FixedU64::saturating_from_rational(1001, 1000);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(999500);
assert_eq!(result, expected);
let y = FixedI64::saturating_from_rational(99, 100);
let result = ln_near_one(y);
let expected = FixedI64::from_inner(-10050334);
assert_eq!(result, expected);
let y = FixedI64::saturating_from_rational(999, 1000);
let result = ln_near_one(y);
let expected = FixedI64::from_inner(-1000500);
assert_eq!(result, expected);
}
#[test]
fn ln_near_one_edge_cases() {
let y = FixedU64::saturating_from_rational(10001, 10000);
let result = ln_near_one(y);
let expected = FixedU64::from_inner(99994);
assert_eq!(result, expected);
let y = FixedI64::saturating_from_rational(9999, 10000);
let result = ln_near_one(y);
let expected = FixedI64::from_inner(-100004);
assert_eq!(result, expected);
}
#[test]
fn dynamic_max_iterations_zero_input() {
let x: FixedU64 = 0.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 1);
}
#[test]
fn dynamic_max_iterations_one_input() {
let x: FixedU64 = 1.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 10); }
#[test]
fn dynamic_max_iterations_small_integers() {
let x: FixedU64 = 2.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 19);
let x: FixedU64 = 5.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 46);
let x: FixedU64 = 10.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 91);
}
#[test]
fn dynamic_max_iterations_fractional_values() {
let x = FixedU64::saturating_from_rational(1, 2);
let result = dynamic_max_iterations(&x);
assert_eq!(result, 1);
let x = FixedU64::saturating_from_rational(9, 10);
let result = dynamic_max_iterations(&x);
assert_eq!(result, 1);
let x = FixedU64::saturating_from_rational(3, 2);
let result = dynamic_max_iterations(&x);
assert_eq!(result, 10);
let x = FixedU64::saturating_from_rational(27, 10);
let result = dynamic_max_iterations(&x);
assert_eq!(result, 19);
}
#[test]
fn dynamic_max_iterations_negative_values() {
let x: FixedI64 = (-1).into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 10);
let x: FixedI64 = (-5).into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 46);
let x: FixedI64 = (-10).into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 91);
let x = FixedI64::saturating_from_rational(-1, 2);
let result = dynamic_max_iterations(&x);
assert_eq!(result, 1);
}
#[test]
fn dynamic_max_iterations_large_values() {
let x: FixedU64 = 100.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 901);
let x: FixedU64 = 1000.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 9001);
let x: FixedU64 = 10000.into();
let result = dynamic_max_iterations(&x);
assert_eq!(result, 90001);
}
#[test]
fn dynamic_max_iterations_saturation_check() {
let x: FixedU64 = (u32::MAX as u64).into();
let result = dynamic_max_iterations(&x);
assert!(result >= 1);
assert_eq!(result, u32::MAX);
}
#[test]
fn to_u32_floor_zero_input() {
let x: FixedU64 = 0.into();
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x: FixedI64 = 0.into();
let result = to_u32_floor(&x);
assert_eq!(result, 0);
}
#[test]
fn to_u32_floor_positive_integers() {
let x: FixedU64 = 1.into();
let result = to_u32_floor(&x);
assert_eq!(result, 1);
let x: FixedU64 = 10.into();
let result = to_u32_floor(&x);
assert_eq!(result, 10);
let x: FixedU64 = 100.into();
let result = to_u32_floor(&x);
assert_eq!(result, 100);
let x: FixedU64 = 1000.into();
let result = to_u32_floor(&x);
assert_eq!(result, 1000);
let x: FixedU64 = 42.into();
let result = to_u32_floor(&x);
assert_eq!(result, 42);
}
#[test]
fn to_u32_floor_fractional_values() {
let x = FixedU64::saturating_from_rational(3, 2);
let result = to_u32_floor(&x);
assert_eq!(result, 1);
let x = FixedU64::saturating_from_rational(27, 10);
let result = to_u32_floor(&x);
assert_eq!(result, 2);
let x = FixedU64::saturating_from_rational(9999, 1000);
let result = to_u32_floor(&x);
assert_eq!(result, 9);
let x = FixedU64::saturating_from_rational(1001, 10);
let result = to_u32_floor(&x);
assert_eq!(result, 100);
let x = FixedU64::saturating_from_rational(1, 2);
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x = FixedU64::saturating_from_rational(9, 10);
let result = to_u32_floor(&x);
assert_eq!(result, 0);
}
#[test]
fn to_u32_floor_negative_values() {
let x: FixedI64 = (-1).into();
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x: FixedI64 = (-10).into();
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x = FixedI64::saturating_from_rational(-1, 2);
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x = FixedI64::saturating_from_rational(-201, 2);
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x: FixedI64 = i64::MIN.into();
let result = to_u32_floor(&x);
assert_eq!(result, 0);
}
#[test]
fn to_u32_floor_boundary_values() {
let x: FixedU64 = (u32::MAX as u64).into();
let result = to_u32_floor(&x);
assert_eq!(result, u32::MAX);
let x: FixedU64 = ((u32::MAX as u64) + 1).into();
let result = to_u32_floor(&x);
assert_eq!(result, u32::MAX);
let x: FixedU64 = ((u32::MAX as u64) + 100).into();
let result = to_u32_floor(&x);
assert_eq!(result, u32::MAX);
}
#[test]
fn to_u32_floor_large_values() {
let x: FixedU64 = 1000000.into();
let result = to_u32_floor(&x);
assert_eq!(result, 1000000);
let x: FixedU64 = 10000000.into();
let result = to_u32_floor(&x);
assert_eq!(result, 10000000);
let x: FixedU64 = u64::MAX.into();
let result = to_u32_floor(&x);
assert_eq!(result, u32::MAX);
}
#[test]
fn to_u32_floor_from_inner_representation() {
let x = FixedU64::from_inner(5_000_000_000);
let result = to_u32_floor(&x);
assert_eq!(result, 5);
let x = FixedU64::from_inner(5_500_000_000);
let result = to_u32_floor(&x);
assert_eq!(result, 5);
let x = FixedU64::from_inner(999_999_999);
let result = to_u32_floor(&x);
assert_eq!(result, 0);
let x = FixedU64::from_inner(1_000_000_000);
let result = to_u32_floor(&x);
assert_eq!(result, 1);
}
#[test]
fn fixed_signed_cast_i64_checked_into() {
let x = FixedI64::saturating_from_integer(5);
assert_eq!(FixedI64::checked_into(x), Some(x));
let x = FixedI64::saturating_from_integer(-7);
assert_eq!(FixedI64::checked_into(x), Some(x));
let x = FixedI64::zero();
assert_eq!(FixedI64::checked_into(x), Some(x));
let x = FixedI64::max_value();
assert_eq!(FixedI64::checked_into(x), Some(x));
let x = FixedI64::min_value();
assert_eq!(FixedI64::checked_into(x), Some(x));
}
#[test]
fn fixed_signed_cast_i64_saturated_into() {
let x = FixedI64::saturating_from_integer(42);
assert_eq!(FixedI64::saturated_into(x), x);
let x = FixedI64::saturating_from_integer(-42);
assert_eq!(FixedI64::saturated_into(x), x);
let x = FixedI64::max_value();
assert_eq!(FixedI64::saturated_into(x), x);
}
#[test]
fn fixed_signed_cast_i64_checked_from() {
let x = FixedI64::saturating_from_integer(3);
assert_eq!(FixedI64::checked_from(x), Some(x));
let x = FixedI64::saturating_from_integer(-3);
assert_eq!(FixedI64::checked_from(x), Some(x));
let x = FixedI64::min_value();
assert_eq!(FixedI64::checked_from(x), Some(x));
}
#[test]
fn fixed_signed_cast_i64_saturated_from() {
let x = FixedI64::saturating_from_integer(10);
assert_eq!(FixedI64::saturated_from(x), x);
let x = FixedI64::saturating_from_integer(-10);
assert_eq!(FixedI64::saturated_from(x), x);
}
#[test]
fn fixed_signed_cast_i64_saturating_closure() {
let x = FixedI64::saturating_from_integer(4);
let result = FixedI64::saturating(x, |v| v.saturating_add(FixedI64::saturating_from_integer(1)));
assert_eq!(result, FixedI64::saturating_from_integer(5));
let x = FixedI64::saturating_from_integer(3);
let result = FixedI64::saturating(x, |v| v.saturating_mul(FixedI64::saturating_from_integer(-1)));
assert_eq!(result, FixedI64::saturating_from_integer(-3));
}
#[test]
fn fixed_signed_cast_i64_checked_closure() {
let x = FixedI64::saturating_from_integer(7);
let result = FixedI64::checked(x, |v| {
v.unwrap_or(FixedI64::zero()).saturating_add(FixedI64::saturating_from_integer(1))
});
assert_eq!(result, Some(FixedI64::saturating_from_integer(8)));
}
#[test]
fn fixed_signed_cast_i64_checked_closure_overflow_is_none() {
let x = FixedI64::max_value();
let result = FixedI64::checked(x, |v| {
v.unwrap_or(FixedI64::zero()).saturating_add(FixedI64::one())
});
assert_eq!(result, None);
}
#[test]
fn fixed_signed_cast_i128_checked_into() {
let x = FixedI128::saturating_from_integer(100);
assert_eq!(FixedI128::checked_into(x), Some(x));
let x = FixedI128::saturating_from_integer(-100);
assert_eq!(FixedI128::checked_into(x), Some(x));
let x = FixedI128::zero();
assert_eq!(FixedI128::checked_into(x), Some(x));
let x = FixedI128::max_value();
assert_eq!(FixedI128::checked_into(x), Some(x));
let x = FixedI128::min_value();
assert_eq!(FixedI128::checked_into(x), Some(x));
}
#[test]
fn fixed_signed_cast_i128_saturated_into() {
let x = FixedI128::saturating_from_integer(999);
assert_eq!(FixedI128::saturated_into(x), x);
let x = FixedI128::saturating_from_integer(-999);
assert_eq!(FixedI128::saturated_into(x), x);
}
#[test]
fn fixed_signed_cast_i128_checked_from() {
let x = FixedI128::saturating_from_integer(50);
assert_eq!(FixedI128::checked_from(x), Some(x));
let x = FixedI128::saturating_from_integer(-50);
assert_eq!(FixedI128::checked_from(x), Some(x));
}
#[test]
fn fixed_signed_cast_i128_saturated_from() {
let x = FixedI128::saturating_from_integer(77);
assert_eq!(FixedI128::saturated_from(x), x);
let x = FixedI128::saturating_from_integer(-77);
assert_eq!(FixedI128::saturated_from(x), x);
}
#[test]
fn fixed_signed_cast_i128_saturating_closure() {
let x = FixedI128::saturating_from_integer(10);
let result = FixedI128::saturating(x, |v| v.saturating_add(FixedI128::saturating_from_integer(5)));
assert_eq!(result, FixedI128::saturating_from_integer(15));
let x = FixedI128::saturating_from_integer(-10);
let result = FixedI128::saturating(x, |v| v.saturating_mul(FixedI128::saturating_from_integer(2)));
assert_eq!(result, FixedI128::saturating_from_integer(-20));
}
#[test]
fn fixed_signed_cast_i128_checked_closure() {
let x = FixedI128::saturating_from_integer(3);
let result = FixedI128::checked(x, |v| {
v.unwrap_or(FixedI128::zero()).saturating_add(FixedI128::saturating_from_integer(2))
});
assert_eq!(result, Some(FixedI128::saturating_from_integer(5)));
}
#[test]
fn fixed_signed_cast_i128_checked_closure_overflow_is_none() {
let x = FixedI128::max_value();
let result = FixedI128::checked(x, |v| {
v.unwrap_or(FixedI128::zero()).saturating_add(FixedI128::one())
});
assert_eq!(result, None);
}
#[test]
fn fixed_signed_cast_u64_checked_into_always_some() {
let x = FixedU64::saturating_from_integer(0);
assert!(FixedU64::checked_into(x).is_some());
let x = FixedU64::saturating_from_integer(1);
let signed = FixedU64::checked_into(x).unwrap();
assert_eq!(signed.into_inner(), x.into_inner() as i128);
let x = FixedU64::max_value();
assert!(FixedU64::checked_into(x).is_some());
}
#[test]
fn fixed_signed_cast_u64_saturated_into_round_trip() {
let values = [
FixedU64::saturating_from_integer(0),
FixedU64::saturating_from_integer(1),
FixedU64::saturating_from_integer(1000),
FixedU64::saturating_from_rational(3, 2), FixedU64::max_value(),
];
for x in values {
let signed = FixedU64::saturated_into(x);
let back = FixedU64::checked_from(signed).unwrap();
assert_eq!(back, x, "round-trip failed for {x:?}");
}
}
#[test]
fn fixed_signed_cast_u64_checked_from_negative_is_none() {
let neg = FixedI128::saturating_from_integer(-1);
assert_eq!(FixedU64::checked_from(neg), None);
let neg = FixedI128::saturating_from_integer(-100);
assert_eq!(FixedU64::checked_from(neg), None);
let neg = FixedI128::min_value();
assert_eq!(FixedU64::checked_from(neg), None);
}
#[test]
fn fixed_signed_cast_u64_checked_from_above_u64_max_is_none() {
let too_large = FixedI128::from_inner(u64::MAX as i128 + 1);
assert_eq!(FixedU64::checked_from(too_large), None);
}
#[test]
fn fixed_signed_cast_u64_checked_from_zero_is_some() {
let zero = FixedI128::zero();
assert_eq!(FixedU64::checked_from(zero), Some(FixedU64::zero()));
}
#[test]
fn fixed_signed_cast_u64_saturated_from_negative_clamps_to_zero() {
let neg = FixedI128::saturating_from_integer(-5);
assert_eq!(FixedU64::saturated_from(neg), FixedU64::zero());
let neg = FixedI128::min_value();
assert_eq!(FixedU64::saturated_from(neg), FixedU64::zero());
}
#[test]
fn fixed_signed_cast_u64_saturated_from_above_max_clamps_to_max() {
let too_large = FixedI128::from_inner(u64::MAX as i128 + 1);
assert_eq!(FixedU64::saturated_from(too_large), FixedU64::from_inner(u64::MAX));
}
#[test]
fn fixed_signed_cast_u64_saturating_closure_with_positive_result() {
let x = FixedU64::saturating_from_integer(3);
let result = FixedU64::saturating(x, |v| v.saturating_add(v));
assert_eq!(result, FixedU64::saturating_from_integer(6));
}
#[test]
fn fixed_signed_cast_u64_saturating_closure_negative_result_clamps() {
let x = FixedU64::saturating_from_integer(2);
let result = FixedU64::saturating(x, |v| v.saturating_mul(FixedI128::saturating_from_integer(-1)));
assert_eq!(result, FixedU64::zero());
}
#[test]
fn fixed_signed_cast_u64_checked_closure_negative_result_is_none() {
let x = FixedU64::saturating_from_integer(5);
let result = FixedU64::checked(x, |v| {
v.unwrap().saturating_mul(FixedI128::saturating_from_integer(-1))
});
assert_eq!(result, None);
}
#[test]
fn fixed_signed_cast_u64_checked_closure_valid_result_is_some() {
let x = FixedU64::saturating_from_integer(10);
let one_unit = FixedI128::from_inner(FixedU64::DIV as i128); let result = FixedU64::checked(x, |v| {
v.unwrap().saturating_add(one_unit)
});
assert_eq!(result, Some(FixedU64::saturating_from_integer(11)));
}
#[test]
fn fixed_signed_cast_u128_checked_into_small_values_are_some() {
let x = FixedU128::saturating_from_integer(0);
assert!(FixedU128::checked_into(x).is_some());
let x = FixedU128::saturating_from_integer(1);
let signed = FixedU128::checked_into(x).unwrap();
assert_eq!(signed.into_inner(), x.into_inner() as i128);
let x = FixedU128::saturating_from_integer(1_000_000);
assert!(FixedU128::checked_into(x).is_some());
}
#[test]
fn fixed_signed_cast_u128_checked_into_above_i128_max_is_none() {
let too_large = FixedU128::from_inner(i128::MAX as u128 + 1);
assert_eq!(FixedU128::checked_into(too_large), None);
assert_eq!(FixedU128::checked_into(FixedU128::max_value()), None);
}
#[test]
fn fixed_signed_cast_u128_saturated_into_large_clamps_to_i128_max() {
let too_large = FixedU128::from_inner(i128::MAX as u128 + 1);
let signed = FixedU128::saturated_into(too_large);
assert_eq!(signed, FixedI128::from_inner(i128::MAX));
let signed_max = FixedU128::saturated_into(FixedU128::max_value());
assert_eq!(signed_max, FixedI128::from_inner(i128::MAX));
}
#[test]
fn fixed_signed_cast_u128_saturated_into_small_values_exact() {
let x = FixedU128::saturating_from_integer(42);
let signed = FixedU128::saturated_into(x);
assert_eq!(signed.into_inner(), x.into_inner() as i128);
}
#[test]
fn fixed_signed_cast_u128_checked_from_negative_is_none() {
let neg = FixedI128::saturating_from_integer(-1);
assert_eq!(FixedU128::checked_from(neg), None);
let neg = FixedI128::min_value();
assert_eq!(FixedU128::checked_from(neg), None);
}
#[test]
fn fixed_signed_cast_u128_checked_from_non_negative_is_some() {
let zero = FixedI128::zero();
assert_eq!(FixedU128::checked_from(zero), Some(FixedU128::zero()));
let pos = FixedI128::saturating_from_integer(100);
let result = FixedU128::checked_from(pos).unwrap();
assert_eq!(result.into_inner(), pos.into_inner() as u128);
}
#[test]
fn fixed_signed_cast_u128_saturated_from_negative_clamps_to_zero() {
let neg = FixedI128::saturating_from_integer(-99);
assert_eq!(FixedU128::saturated_from(neg), FixedU128::zero());
let neg = FixedI128::min_value();
assert_eq!(FixedU128::saturated_from(neg), FixedU128::zero());
}
#[test]
fn fixed_signed_cast_u128_saturated_from_non_negative_exact() {
let pos = FixedI128::saturating_from_integer(500);
let result = FixedU128::saturated_from(pos);
assert_eq!(result.into_inner(), pos.into_inner() as u128);
let zero = FixedI128::zero();
assert_eq!(FixedU128::saturated_from(zero), FixedU128::zero());
}
#[test]
fn fixed_signed_cast_u128_round_trip_for_representable_values() {
let values = [
FixedU128::saturating_from_integer(0),
FixedU128::saturating_from_integer(1),
FixedU128::saturating_from_integer(1_000_000),
FixedU128::saturating_from_rational(7, 3),
];
for x in values {
let signed = FixedU128::saturated_into(x);
let back = FixedU128::checked_from(signed).unwrap();
assert_eq!(back, x, "round-trip failed for {x:?}");
}
}
#[test]
fn fixed_signed_cast_u128_saturating_closure_valid() {
let x = FixedU128::saturating_from_integer(4);
let result = FixedU128::saturating(x, |v| v.saturating_add(FixedI128::saturating_from_integer(6)));
assert_eq!(result, FixedU128::saturating_from_integer(10));
}
#[test]
fn fixed_signed_cast_u128_saturating_closure_negative_clamps_to_zero() {
let x = FixedU128::saturating_from_integer(3);
let result = FixedU128::saturating(x, |v| v.saturating_mul(FixedI128::saturating_from_integer(-2)));
assert_eq!(result, FixedU128::zero());
}
#[test]
fn fixed_signed_cast_u128_checked_closure_negative_is_none() {
let x = FixedU128::saturating_from_integer(5);
let result = FixedU128::checked(x, |v| {
v.unwrap_or(FixedI128::zero())
.saturating_mul(FixedI128::saturating_from_integer(-1))
});
assert_eq!(result, None);
}
#[test]
fn fixed_signed_cast_u128_checked_closure_valid_is_some() {
let x = FixedU128::saturating_from_integer(20);
let result = FixedU128::checked(x, |v| {
v.unwrap_or(FixedI128::zero())
.saturating_add(FixedI128::saturating_from_integer(5))
});
assert_eq!(result, Some(FixedU128::saturating_from_integer(25)));
}
#[test]
fn fixed_signed_cast_u128_checked_into_none_propagated_through_closure() {
let too_large = FixedU128::from_inner(i128::MAX as u128 + 1);
let result = FixedU128::checked(too_large, |v| {
v.unwrap_or(FixedI128::zero()) });
assert_eq!(result, Some(FixedU128::zero()));
}
}