rust_poly/
scalar.rs

1//! Traits for the coefficients of polynomials
2
3use f128::f128;
4use num::{traits::Float, Complex, FromPrimitive, Num, ToPrimitive};
5use std::{
6    fmt::Display,
7    ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign},
8};
9
10/// A rational number, less restrictive than `num::Float`
11pub trait Rational: std::ops::Div<Output = Self> + num::One + ToPrimitive + FromPrimitive {
12    fn recip(self) -> Self {
13        Self::one() / self
14    }
15
16    fn upper_bound() -> Self;
17}
18
19impl Rational for f32 {
20    fn recip(self) -> Self {
21        f32::recip(self)
22    }
23
24    fn upper_bound() -> Self {
25        <f32 as Float>::max_value()
26    }
27}
28
29impl Rational for f64 {
30    fn recip(self) -> Self {
31        f64::recip(self)
32    }
33
34    fn upper_bound() -> Self {
35        <f64 as Float>::max_value()
36    }
37}
38
39impl Rational for f128 {
40    fn recip(self) -> Self {
41        Float::recip(self)
42    }
43
44    fn upper_bound() -> Self {
45        <f128 as Float>::max_value()
46    }
47}
48
49// pub trait ComplexScalar: Scalar {
50//     type ComponentScalar;
51// }
52
53// impl ComplexScalar for Complex64 {
54//     type ComponentScalar = f64;
55// }
56// impl ComplexScalar for Complex32 {
57//     type ComponentScalar = f32;
58// }
59
60/// The trait bounds necessary to provide the basic functionality of this crate.
61#[allow(clippy::module_name_repetitions)]
62pub trait RealScalar:
63    Clone
64    + PartialEq
65    + std::fmt::Debug
66    + Num
67    + FromPrimitive
68    + ToPrimitive
69    + SafeConstants
70    + std::ops::Neg<Output = Self>
71    + 'static
72    + AddAssign
73    + SubAssign
74    + MulAssign
75    + DivAssign
76    + RemAssign
77    //+ MulAdd<Output = Self>
78    //+ MulAddAssign
79    + Display
80    + PartialEq
81    + PartialOrd
82    //+ UpperBounded
83    + Rational
84{
85}
86impl<
87        T: Clone
88            + PartialEq
89            + PartialOrd
90            + std::fmt::Debug
91            + Num
92            + FromPrimitive
93            + ToPrimitive
94            + SafeConstants
95            + std::ops::Neg<Output = Self>
96            + AddAssign
97            + SubAssign
98            + MulAssign
99            + DivAssign
100            + RemAssign
101            //+ MulAdd<Output = Self>
102            //+ MulAddAssign
103            + 'static
104            + PartialEq
105            + PartialOrd
106            //+ UpperBounded
107            + Rational
108            + Display,
109    > RealScalar for T
110{
111}
112
113/// A number that has a smallest positive _safe_ value for denominators and a largest
114/// positive _safe_ value for numerators.
115///
116/// These are arbitrary ranges, but they need to fulfill a few requirements:
117/// - `big_safe` should be very large, enough that practically most numbers will be smaller
118/// - `small_safe` should be very small, enough that practically most numbers will be bigger
119/// - `big_safe / small_safe <= MAX` where MAX is the largerst finite number representible
120///
121/// Knowledge of these numbers make it possible to check for overflow in division,
122/// if `numberator <= big_safe` and `denominator >= small_safe` the division will
123/// always be finite.
124///
125/// If either numerator or denominator is outside of the range, then the division
126/// is not guaranteed to be finite, but is not guaranteed to overflow either.
127///
128/// The trait additionally provides a minimum safe value for reciprocals, i.e.
129/// if `numerator <= 1.0`.
130pub trait SafeConstants {
131    /// Smallest value that is safe for reciprocals
132    fn tiny_safe() -> Self;
133
134    /// Smallest value that is safe for use as a denominator
135    fn small_safe() -> Self;
136
137    /// Biggest value that is safe for use as a numerator
138    fn large_safe() -> Self;
139
140    /// If the number is smaller than [`SafeConstants::small_safe`], i.e. it is not safe for division
141    fn is_small(&self) -> bool;
142
143    /// If the number is smaller than [`SafeConstants::tiny_safe`], i.e. it is not safe for reciprocals
144    fn is_tiny(&self) -> bool;
145
146    /// If the number is larger than [`SafeConstants::large_safe`], i.e. it is not safe for division
147    fn is_large(&self) -> bool;
148}
149
150macro_rules! safe_constants_float_impl {
151    ($t:ty) => {
152        impl SafeConstants for $t {
153            fn tiny_safe() -> Self {
154                Self::MIN_POSITIVE
155            }
156
157            fn small_safe() -> Self {
158                Self::MIN_POSITIVE.sqrt() / Self::EPSILON
159            }
160
161            fn large_safe() -> Self {
162                Self::MAX * Self::small_safe()
163            }
164
165            fn is_tiny(&self) -> bool {
166                self.abs() < Self::tiny_safe()
167            }
168
169            fn is_small(&self) -> bool {
170                self.abs() < Self::small_safe()
171            }
172
173            fn is_large(&self) -> bool {
174                self.abs() > Self::large_safe()
175            }
176        }
177    };
178}
179
180safe_constants_float_impl!(f32);
181safe_constants_float_impl!(f64);
182safe_constants_float_impl!(f128);
183
184impl<T: SafeConstants> SafeConstants for Complex<T> {
185    fn tiny_safe() -> Self {
186        Self {
187            re: T::tiny_safe(),
188            im: T::tiny_safe(),
189        }
190    }
191
192    fn small_safe() -> Self {
193        Self {
194            re: T::small_safe(),
195            im: T::small_safe(),
196        }
197    }
198
199    fn large_safe() -> Self {
200        Self {
201            re: T::large_safe(),
202            im: T::large_safe(),
203        }
204    }
205
206    fn is_small(&self) -> bool {
207        self.re.is_small() && self.im.is_small()
208    }
209
210    fn is_tiny(&self) -> bool {
211        self.re.is_tiny() && self.im.is_tiny()
212    }
213
214    fn is_large(&self) -> bool {
215        self.re.is_large() || self.im.is_large()
216    }
217}