//! # Real Number //! Most algorithms in `smartcore` rely on basic linear algebra operations like dot product, matrix decomposition and other subroutines that are defined for a set of real numbers, ℝ. //! This module defines real number and some useful functions that are used in [Linear Algebra](../../linalg/index.html) module. use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; use num_traits::Float; use crate::numbers::basenum::Number; use crate::rand_custom::get_rng_impl; /// Defines real number /// pub trait RealNumber: Number + Float { /// Copy sign from `sign` - another real number fn copysign(self, sign: Self) -> Self; /// Calculates natural \\( \ln(1+e^x) \\) without overflow. fn ln_1pe(self) -> Self; /// Efficient implementation of Sigmoid function, \\( S(x) = \frac{1}{1 + e^{-x}} \\), see [Sigmoid function](https://en.wikipedia.org/wiki/Sigmoid_function) fn sigmoid(self) -> Self; /// Returns pseudorandom number between 0 and 1 fn rand() -> Self; /// Returns 2 fn two() -> Self; /// Returns .5 fn half() -> Self; /// Returns \\( x^2 \\) fn square(self) -> Self { self * self } /// Raw transmutation to u32 fn to_f32_bits(self) -> u32; /// Raw transmutation to u64 fn to_f64_bits(self) -> u64; } impl RealNumber for f64 { fn copysign(self, sign: Self) -> Self { self.copysign(sign) } fn ln_1pe(self) -> f64 { if self > 15. { self } else { self.exp().ln_1p() } } fn sigmoid(self) -> f64 { if self < -40. { 0. } else if self > 40. { 1. } else { 1. / (1. + f64::exp(-self)) } } fn rand() -> f64 { let mut small_rng = get_rng_impl(None); let mut rngs: Vec = (0..3) .map(|_| SmallRng::from_rng(&mut small_rng).unwrap()) .collect(); rngs[0].gen::() } fn two() -> Self { 2f64 } fn half() -> Self { 0.5f64 } fn to_f32_bits(self) -> u32 { self.to_bits() as u32 } fn to_f64_bits(self) -> u64 { self.to_bits() } } impl RealNumber for f32 { fn copysign(self, sign: Self) -> Self { self.copysign(sign) } fn ln_1pe(self) -> f32 { if self > 15. { self } else { self.exp().ln_1p() } } fn sigmoid(self) -> f32 { if self < -40. { 0. } else if self > 40. { 1. } else { 1. / (1. + f32::exp(-self)) } } fn rand() -> f32 { let mut small_rng = get_rng_impl(None); let mut rngs: Vec = (0..3) .map(|_| SmallRng::from_rng(&mut small_rng).unwrap()) .collect(); rngs[0].gen::() } fn two() -> Self { 2f32 } fn half() -> Self { 0.5f32 } fn to_f32_bits(self) -> u32 { self.to_bits() } fn to_f64_bits(self) -> u64 { self.to_bits() as u64 } } #[cfg(test)] mod tests { use super::*; use std::str::FromStr; #[test] fn sigmoid() { assert_eq!(1.0.sigmoid(), 0.7310585786300049); assert_eq!(41.0.sigmoid(), 1.); assert_eq!((-41.0).sigmoid(), 0.); } #[test] fn f32_from_string() { assert_eq!(f32::from_str("1.111111").unwrap(), 1.111111) } #[test] fn f64_from_string() { assert_eq!(f64::from_str("1.111111111").unwrap(), 1.111111111) } #[test] fn f64_rand() { f64::rand(); } #[test] fn f32_rand() { f32::rand(); } }