use num_traits::{Float, Num, NumCast, One, Zero};
use std::fmt::Debug;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
pub trait ScientificNumber:
Num
+ Clone
+ Copy
+ PartialOrd
+ Debug
+ Zero
+ One
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ NumCast
{
fn abs(self) -> Self;
fn sqrt(self) -> Self;
fn square(self) -> Self {
self * self
}
fn max(self, other: Self) -> Self;
fn min(self, other: Self) -> Self;
fn is_finite(self) -> bool;
fn to_f64(self) -> Option<f64>;
fn from_f64(value: f64) -> Option<Self>;
}
pub trait RealNumber: ScientificNumber + Float {
fn epsilon() -> Self;
fn exp(self) -> Self;
fn ln(self) -> Self;
fn log10(self) -> Self;
fn log2(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn asin(self) -> Self;
fn acos(self) -> Self;
fn atan(self) -> Self;
fn atan2(self, other: Self) -> Self;
fn powf(self, n: Self) -> Self;
fn powi(self, n: i32) -> Self;
fn factorial(self) -> Self;
}
pub trait ComplexNumber: ScientificNumber {
type RealPart: RealNumber;
fn re(&self) -> Self::RealPart;
fn im(&self) -> Self::RealPart;
fn new(re: Self::RealPart, im: Self::RealPart) -> Self;
fn conj(self) -> Self;
fn abs(self) -> Self::RealPart;
fn arg(self) -> Self::RealPart;
fn to_polar(self) -> (Self::RealPart, Self::RealPart);
fn from_polar(r: Self::RealPart, theta: Self::RealPart) -> Self;
fn exp(self) -> Self;
fn ln(self) -> Self;
fn powc(self, exp: Self) -> Self;
fn powf(self, exp: Self::RealPart) -> Self;
fn sqrt(self) -> Self;
}
pub trait ScientificInteger: ScientificNumber + Eq {
fn gcd(self, other: Self) -> Self;
fn lcm(self, other: Self) -> Self;
fn is_prime(self) -> bool;
fn is_even(self) -> bool;
fn is_odd(self) -> bool;
fn mod_pow(self, exp: Self, modulus: Self) -> Self;
fn factorial(self) -> Self;
fn binomial(self, k: Self) -> Self;
}
impl ScientificNumber for f32 {
fn abs(self) -> Self {
self.abs()
}
fn sqrt(self) -> Self {
self.sqrt()
}
fn max(self, other: Self) -> Self {
self.max(other)
}
fn min(self, other: Self) -> Self {
self.min(other)
}
fn is_finite(self) -> bool {
self.is_finite()
}
fn to_f64(self) -> Option<f64> {
Some(self as f64)
}
fn from_f64(value: f64) -> Option<Self> {
if value.is_finite() && value <= f32::MAX as f64 && value >= f32::MIN as f64 {
Some(value as f32)
} else {
None
}
}
}
impl RealNumber for f32 {
fn epsilon() -> Self {
f32::EPSILON
}
fn exp(self) -> Self {
self.exp()
}
fn ln(self) -> Self {
self.ln()
}
fn log10(self) -> Self {
self.log10()
}
fn log2(self) -> Self {
self.log2()
}
fn sin(self) -> Self {
self.sin()
}
fn cos(self) -> Self {
self.cos()
}
fn tan(self) -> Self {
self.tan()
}
fn sinh(self) -> Self {
self.sinh()
}
fn cosh(self) -> Self {
self.cosh()
}
fn tanh(self) -> Self {
self.tanh()
}
fn asin(self) -> Self {
self.asin()
}
fn acos(self) -> Self {
self.acos()
}
fn atan(self) -> Self {
self.atan()
}
fn atan2(self, other: Self) -> Self {
self.atan2(other)
}
fn powf(self, n: Self) -> Self {
self.powf(n)
}
fn powi(self, n: i32) -> Self {
self.powi(n)
}
fn factorial(self) -> Self {
if self < 0.0 {
return f32::NAN;
}
if self != self.trunc() || self > 100.0 {
const SQRT_TWO_PI: f32 = 2.506_628_3;
return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
}
let mut result = 1.0;
let n = self as u32;
for i in 2..=n {
result *= i as f32;
}
result
}
}
impl ScientificNumber for f64 {
fn abs(self) -> Self {
self.abs()
}
fn sqrt(self) -> Self {
self.sqrt()
}
fn max(self, other: Self) -> Self {
self.max(other)
}
fn min(self, other: Self) -> Self {
self.min(other)
}
fn is_finite(self) -> bool {
self.is_finite()
}
fn to_f64(self) -> Option<f64> {
Some(self)
}
fn from_f64(value: f64) -> Option<Self> {
Some(value)
}
}
impl RealNumber for f64 {
fn epsilon() -> Self {
f64::EPSILON
}
fn exp(self) -> Self {
self.exp()
}
fn ln(self) -> Self {
self.ln()
}
fn log10(self) -> Self {
self.log10()
}
fn log2(self) -> Self {
self.log2()
}
fn sin(self) -> Self {
self.sin()
}
fn cos(self) -> Self {
self.cos()
}
fn tan(self) -> Self {
self.tan()
}
fn sinh(self) -> Self {
self.sinh()
}
fn cosh(self) -> Self {
self.cosh()
}
fn tanh(self) -> Self {
self.tanh()
}
fn asin(self) -> Self {
self.asin()
}
fn acos(self) -> Self {
self.acos()
}
fn atan(self) -> Self {
self.atan()
}
fn atan2(self, other: Self) -> Self {
self.atan2(other)
}
fn powf(self, n: Self) -> Self {
self.powf(n)
}
fn powi(self, n: i32) -> Self {
self.powi(n)
}
fn factorial(self) -> Self {
if self < 0.0 {
return f64::NAN;
}
if self != self.trunc() || self > 170.0 {
const SQRT_TWO_PI: f64 = 2.5066282746310002;
return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
}
let mut result = 1.0;
let n = self as u32;
for i in 2..=n {
result *= i as f64;
}
result
}
}
impl ScientificNumber for i32 {
fn abs(self) -> Self {
self.abs()
}
fn sqrt(self) -> Self {
(self as f64).sqrt() as i32
}
fn max(self, other: Self) -> Self {
std::cmp::max(self, other)
}
fn min(self, other: Self) -> Self {
std::cmp::min(self, other)
}
fn is_finite(self) -> bool {
true }
fn to_f64(self) -> Option<f64> {
Some(self as f64)
}
fn from_f64(value: f64) -> Option<Self> {
if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
Some(value as i32)
} else {
None
}
}
}
impl ScientificInteger for i32 {
fn gcd(self, other: Self) -> Self {
let mut a = self.abs();
let mut b = other.abs();
if a == 0 {
return b;
}
if b == 0 {
return a;
}
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
a
}
fn lcm(self, other: Self) -> Self {
if self == 0 || other == 0 {
return 0;
}
let gcd = self.gcd(other);
(self / gcd) * other
}
fn is_prime(self) -> bool {
if self <= 1 {
return false;
}
if self <= 3 {
return true;
}
if self % 2 == 0 || self % 3 == 0 {
return false;
}
let mut i = 5;
while i * i <= self {
if self % i == 0 || self % (i + 2) == 0 {
return false;
}
i += 6;
}
true
}
fn is_even(self) -> bool {
self % 2 == 0
}
fn is_odd(self) -> bool {
self % 2 != 0
}
fn mod_pow(self, exp: Self, modulus: Self) -> Self {
if modulus == 1 {
return 0;
}
let mut base = self % modulus;
let mut result = 1;
let mut exponent = exp;
while exponent > 0 {
if exponent % 2 == 1 {
result = (result * base) % modulus;
}
exponent >>= 1;
base = (base * base) % modulus;
}
result
}
fn factorial(self) -> Self {
if self < 0 {
panic!("Factorial not defined for negative numbers");
}
let mut result = 1;
for i in 2..=self {
result *= i;
}
result
}
fn binomial(self, k: Self) -> Self {
if k < 0 || k > self {
return 0;
}
let k = std::cmp::min(k, self - k);
let mut result = 1;
for i in 0..k {
result = result * (self - i) / (i + 1);
}
result
}
}
pub trait NumericConversion<T> {
fn try_convert(self) -> Option<T>;
fn convert_or(self, default: T) -> T;
fn convert(self) -> T;
}
impl<F, T> NumericConversion<T> for F
where
F: NumCast,
T: NumCast,
{
fn try_convert(self) -> Option<T> {
num_traits::cast(self)
}
fn convert_or(self, default: T) -> T {
self.try_convert().unwrap_or(default)
}
fn convert(self) -> T {
self.try_convert().expect("Numeric conversion failed")
}
}
pub trait AngleConversion {
fn to_radians(self) -> Self;
fn to_degrees(self) -> Self;
}
impl<T: RealNumber> AngleConversion for T {
fn to_radians(self) -> Self {
let pi = T::from_f64(std::f64::consts::PI).unwrap();
self * pi / T::from_f64(180.0).unwrap()
}
fn to_degrees(self) -> Self {
let pi = T::from_f64(std::f64::consts::PI).unwrap();
self * T::from_f64(180.0).unwrap() / pi
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Scalar<T: ScientificNumber>(pub T);
impl<T: ScientificNumber> Scalar<T> {
pub fn new(value: T) -> Self {
Scalar(value)
}
pub fn value(&self) -> T {
self.0
}
}
impl<T: ScientificNumber> From<T> for Scalar<T> {
fn from(value: T) -> Self {
Scalar(value)
}
}
impl<T: ScientificNumber> Add for Scalar<T> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Scalar(self.0 + other.0)
}
}
impl<T: ScientificNumber> Sub for Scalar<T> {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Scalar(self.0 - other.0)
}
}
impl<T: ScientificNumber> Mul for Scalar<T> {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Scalar(self.0 * other.0)
}
}
impl<T: ScientificNumber> Div for Scalar<T> {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Scalar(self.0 / other.0)
}
}
impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
type Output = Self;
fn neg(self) -> Self::Output {
Scalar(self.0.neg())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scientific_number_f32() {
let a: f32 = 3.0;
let b: f32 = 4.0;
assert_eq!(a.abs(), 3.0);
assert_eq!(a.sqrt(), (3.0_f32).sqrt());
assert_eq!(a.square(), 9.0);
assert_eq!(a.max(b), 4.0);
assert_eq!(a.min(b), 3.0);
assert!(a.is_finite());
assert_eq!(a.to_f64(), Some(3.0));
assert_eq!(f32::from_f64(3.5), Some(3.5));
}
#[test]
fn test_scientific_number_f64() {
let a: f64 = 3.0;
let b: f64 = 4.0;
assert_eq!(a.abs(), 3.0);
assert_eq!(a.sqrt(), (3.0_f64).sqrt());
assert_eq!(a.square(), 9.0);
assert_eq!(a.max(b), 4.0);
assert_eq!(a.min(b), 3.0);
assert!(a.is_finite());
assert_eq!(a.to_f64(), Some(3.0));
assert_eq!(f64::from_f64(3.5), Some(3.5));
}
#[test]
fn test_real_number_f32() {
let a: f32 = 3.0;
assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
assert_eq!(a.exp(), (3.0_f32).exp());
assert_eq!(a.ln(), (3.0_f32).ln());
assert_eq!(a.sin(), (3.0_f32).sin());
assert_eq!(a.cos(), (3.0_f32).cos());
assert_eq!(a.powf(2.0), 9.0);
}
#[test]
fn test_real_number_f64() {
let a: f64 = 3.0;
assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
assert_eq!(a.exp(), (3.0_f64).exp());
assert_eq!(a.ln(), (3.0_f64).ln());
assert_eq!(a.sin(), (3.0_f64).sin());
assert_eq!(a.cos(), (3.0_f64).cos());
assert_eq!(a.powf(2.0), 9.0);
}
#[test]
fn test_scientific_integer_i32() {
let a: i32 = 12;
let b: i32 = 8;
assert_eq!(a.gcd(b), 4);
assert_eq!(a.lcm(b), 24);
assert!(!a.is_prime());
assert!(11_i32.is_prime());
assert!(a.is_even());
assert!(!a.is_odd());
assert_eq!(a.mod_pow(2, 10), 4); assert_eq!(5_i32.factorial(), 120);
assert_eq!(5_i32.binomial(2), 10); }
#[test]
fn test_numeric_conversion() {
let a: f64 = 3.5;
let b: i32 = a.try_convert().unwrap();
assert_eq!(b, 3);
let c: f32 = 100.5;
let d: f64 = c.convert();
assert_eq!(d, 100.5);
let e: i32 = 100;
let f: f32 = e.convert();
assert_eq!(f, 100.0);
}
#[test]
fn test_angle_conversion() {
let degrees: f64 = 180.0;
let radians = degrees.to_radians();
assert_eq!(radians, std::f64::consts::PI);
let radians: f64 = std::f64::consts::PI / 2.0;
let degrees = radians.to_degrees();
assert_eq!(degrees, 90.0);
}
#[test]
fn test_scalar() {
let a = Scalar::new(3.0_f64);
let b = Scalar::new(4.0_f64);
assert_eq!((a + b).value(), 7.0);
assert_eq!((a - b).value(), -1.0);
assert_eq!((a * b).value(), 12.0);
assert_eq!((a / b).value(), 0.75);
assert_eq!((-a).value(), -3.0);
let c: Scalar<f64> = 5.0.into();
assert_eq!(c.value(), 5.0);
}
}