Mon, 24 Oct 2022 10:52:19 +0300
Added type for numerical errors
| 0 | 1 | ///! Some useful (numerical) types and type traits |
| 2 | ||
| 3 | use trait_set::trait_set; | |
| 4 | pub use num_traits::Float as NumTraitsFloat; // needed to re-export functions. | |
| 5 | pub use num_traits::cast::AsPrimitive; | |
| 6 | ||
| 7 | /// Typical integer type | |
| 8 | #[allow(non_camel_case_types)] | |
| 9 | pub type int = i64; | |
| 10 | ||
| 11 | /// Typical unsigned integer type | |
| 12 | #[allow(non_camel_case_types)] | |
| 13 | pub type uint = u64; | |
| 14 | ||
| 15 | /// Typical floating point number type | |
| 16 | #[allow(non_camel_case_types)] | |
| 17 | pub type float = f64; | |
| 18 | ||
| 19 | /// Casts of abstract numerical types to others via the standard `as` keyword. | |
| 20 | pub trait CastFrom<T : 'static + Copy> : num_traits::cast::AsPrimitive<T> { | |
| 21 | fn cast_from(other : T) -> Self; | |
| 22 | } | |
| 23 | ||
| 24 | macro_rules! impl_casts { | |
| 25 | ($($type:ty)*) => { $( | |
| 26 | impl_casts!(@phase2, $type, | |
| 27 | u8 u16 u32 u64 u128 usize | |
| 28 | i8 i16 i32 i64 i128 isize | |
| 29 | f32 f64); | |
| 30 | )* }; | |
| 31 | (@phase2, $type:ty, $($type2:ty)*) => { $( | |
| 32 | impl CastFrom<$type2> for $type { | |
| 33 | #[inline] | |
| 34 | fn cast_from(other : $type2) -> Self { other as $type } | |
| 35 | } | |
| 36 | )* }; | |
| 37 | } | |
| 38 | ||
| 39 | impl_casts!(u8 u16 u32 u64 u128 usize | |
| 40 | i8 i16 i32 i64 i128 isize | |
| 41 | f32 f64); | |
| 42 | ||
| 43 | /// Trait for numeric types | |
| 44 | pub trait Num : 'static + Copy + num::Num + num_traits::NumAssign | |
| 45 | + std::iter::Sum + std::iter::Product | |
| 46 | + std::fmt::Debug + std::fmt::Display + serde::Serialize | |
| 47 | + CastFrom<u8> + CastFrom<u16> + CastFrom<u32> + CastFrom<u64> | |
| 48 | + CastFrom<u128> + CastFrom<usize> | |
| 49 | + CastFrom<i8> + CastFrom<i16> + CastFrom<i32> + CastFrom<i64> | |
| 50 | + CastFrom<i128> + CastFrom<isize> | |
| 51 | + CastFrom<f32> + CastFrom<f64> { | |
| 52 | ||
| 53 | const ZERO : Self; | |
| 54 | const ONE : Self; | |
| 55 | const TWO : Self; | |
| 56 | /// Generic version of <Self>::MAX; | |
| 57 | const RANGE_MAX : Self; | |
| 58 | /// Generic version of <Self>::MIN; | |
| 59 | const RANGE_MIN : Self; | |
| 60 | } | |
| 61 | ||
| 62 | /// Trait for signed numeric types | |
| 63 | pub trait SignedNum : Num + num::Signed + std::ops::Neg<Output=Self> {} | |
| 64 | impl<U : Num + num::Signed + std::ops::Neg<Output=Self>> SignedNum for U { } | |
| 65 | ||
| 66 | /// Trait for floating point numbers | |
| 67 | pub trait Float : SignedNum + num::Float + From<Self::CompatibleSize> { | |
| 68 | /// An unsigned integer that can be used for indexing operations and | |
| 69 | /// converted to F without loss. | |
| 70 | type CompatibleSize : CompatibleUnsigned<Self>; | |
| 71 | ||
| 72 | const PI : Self; | |
| 73 | const E : Self; | |
| 74 | const EPSILON : Self; | |
| 75 | const SQRT_2 : Self; | |
| 76 | const INFINITY : Self; | |
| 77 | const NEG_INFINITY : Self; | |
| 78 | const FRAC_2_SQRT_PI : Self; | |
| 79 | } | |
| 80 | ||
| 81 | /// Trait for integers | |
| 82 | pub trait Integer : Num + num::Integer {} | |
| 83 | ||
| 84 | /// Trait for unsigned integers | |
| 85 | pub trait Unsigned : Num + Integer + num::Unsigned {} | |
| 86 | ||
| 87 | /// Trait for signed integers | |
| 88 | pub trait Signed : SignedNum + Integer {} | |
| 89 | ||
| 90 | macro_rules! impl_num_consts { | |
| 91 | ($($type:ty)*) => { $( | |
| 92 | impl Num for $type { | |
| 93 | const ZERO : Self = 0 as $type; | |
| 94 | const ONE : Self = 1 as $type; | |
| 95 | const TWO : Self = 2 as $type; | |
| 96 | const RANGE_MAX : Self = <$type>::MAX; | |
| 97 | const RANGE_MIN : Self = <$type>::MIN; | |
| 98 | } | |
| 99 | )* } | |
| 100 | } | |
| 101 | ||
| 102 | macro_rules! impl_integers { | |
| 103 | ($signed:ty : $($type:ty)*) => { $( | |
| 104 | impl_num_consts!($type); | |
| 105 | impl Integer for $type {} | |
| 106 | impl $signed for $type {} | |
| 107 | )* } | |
| 108 | } | |
| 109 | ||
| 110 | impl_integers!(Signed: i8 i16 i32 i64 i128 isize); | |
| 111 | impl_integers!(Unsigned: u8 u16 u32 u64 u128 usize); | |
| 112 | ||
| 113 | impl_num_consts!(f32 f64); | |
| 114 | ||
| 115 | impl Float for f64 { | |
| 116 | #[cfg(any(target_pointer_width = "128", target_pointer_width = "64"))] | |
| 117 | type CompatibleSize = u32; | |
| 118 | #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] | |
| 119 | type CompatibleSize = usize; | |
| 120 | ||
| 121 | const PI : Self = std::f64::consts::PI; | |
| 122 | const E : Self = std::f64::consts::E; | |
| 123 | const EPSILON : Self = std::f64::EPSILON; | |
| 124 | const SQRT_2 : Self = std::f64::consts::SQRT_2; | |
| 125 | const INFINITY : Self = std::f64::INFINITY; | |
| 126 | const NEG_INFINITY : Self = std::f64::NEG_INFINITY; | |
| 127 | const FRAC_2_SQRT_PI : Self = std::f64::consts::FRAC_2_SQRT_PI; | |
| 128 | } | |
| 129 | ||
| 130 | impl Float for f32 { | |
| 131 | #[cfg(any(target_pointer_width = "128", target_pointer_width = "64", target_pointer_width = "32"))] | |
| 132 | type CompatibleSize = u16; | |
| 133 | #[cfg(any(target_pointer_width = "16"))] | |
| 134 | type CompatibleSize = usize; | |
| 135 | ||
| 136 | const PI : Self = std::f32::consts::PI; | |
| 137 | const E : Self = std::f32::consts::E; | |
| 138 | const EPSILON : Self = std::f32::EPSILON; | |
| 139 | const SQRT_2 : Self = std::f32::consts::SQRT_2; | |
| 140 | const INFINITY : Self = std::f32::INFINITY; | |
| 141 | const NEG_INFINITY : Self = std::f32::NEG_INFINITY; | |
| 142 | const FRAC_2_SQRT_PI : Self = std::f32::consts::FRAC_2_SQRT_PI; | |
| 143 | } | |
| 144 | ||
| 145 | trait_set! { | |
| 146 | pub trait CompatibleUnsigned<F : Float> = Unsigned + Into<F>; | |
| 147 | pub trait CompatibleSigned<F : Float> = Signed + Into<F>; | |
| 148 | } |