float/
lib.rs

1#![deny(missing_docs)]
2
3//! Traits for generic floats in game programming
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign};
5
6/// Convenience trait for floats.
7pub trait Float:
8    'static + Send + Sync
9    + Copy + Radians + One + Zero + Sqrt
10    + FromPrimitive
11    + Min + Max + Signum + Powf
12    + Trig
13    + PartialEq
14    + PartialOrd
15    + Add<Self, Output = Self> + AddAssign<Self>
16    + Mul<Self, Output = Self> + MulAssign<Self>
17    + Sub<Self, Output = Self> + SubAssign<Self>
18    + Div<Self, Output = Self> + DivAssign<Self>
19    + Rem<Self, Output = Self> + RemAssign<Self>
20    + Neg<Output = Self>
21    + Trig {}
22
23impl<T> Float for T where
24    T: 'static + Send + Sync
25    + Copy + Radians + One + Zero + Sqrt
26    + FromPrimitive
27    + Min + Max + Signum + Powf
28    + Trig
29    + PartialEq
30    + PartialOrd
31    + Add<T, Output = T> + AddAssign<T>
32    + Mul<T, Output = T> + MulAssign<T>
33    + Sub<T, Output = T> + SubAssign<T>
34    + Div<T, Output = T> + DivAssign<T>
35    + Rem<T, Output = T> + RemAssign<T>
36    + Neg<Output = T>
37    + Trig {}
38
39/// Minimum value.
40pub trait Min {
41    /// Returns the minimum value of self or other.
42    fn min(self, other: Self) -> Self;
43}
44
45impl Min for f32 {
46    #[inline(always)]
47    fn min(self, other: Self) -> Self { self.min(other) }
48}
49
50impl Min for f64 {
51    #[inline(always)]
52    fn min(self, other: Self) -> Self { self.min(other) }
53}
54
55/// Maximum value.
56pub trait Max {
57    /// Returns the maximum value of self or other.
58    fn max(self, other: Self) -> Self;
59}
60
61impl Max for f32 {
62    #[inline(always)]
63    fn max(self, other: Self) -> Self { self.max(other) }
64}
65
66impl Max for f64 {
67    #[inline(always)]
68    fn max(self, other: Self) -> Self { self.max(other) }
69}
70
71/// The sign of the number.
72pub trait Signum {
73    /// Returns number representing the sign of self
74    fn signum(self) -> Self;
75}
76
77impl Signum for f32 {
78    #[inline(always)]
79    fn signum(self) -> Self { self.signum() }
80}
81
82impl Signum for f64 {
83    #[inline(always)]
84    fn signum(self) -> Self { self.signum() }
85}
86
87/// Floating number power.
88pub trait Powf {
89    /// Returns floating power of the number.
90    fn powf(self, other: Self) -> Self;
91}
92
93impl Powf for f32 {
94    #[inline(always)]
95    fn powf(self, other: Self) -> Self { self.powf(other) }
96}
97
98impl Powf for f64 {
99    #[inline(always)]
100    fn powf(self, other: Self) -> Self { self.powf(other) }
101}
102
103/// Useful constants for radians.
104pub trait Radians {
105    /// Returns radians corresponding to 90 degrees.
106    fn _90() -> Self;
107
108    /// Returns radians corresponding to 180 degrees.
109    fn _180() -> Self;
110
111    /// Returns radians corresponding to 360 degrees.
112    fn _360() -> Self;
113
114    /// Convert a value to radians from degrees.
115    /// Equivalent to ```value * (π / 180)```.
116    fn deg_to_rad(self) -> Self;
117
118    /// Convert a value to degrees from radians.
119    /// Equivalent to ```value * (180 / π)```.
120    fn rad_to_deg(self) -> Self;
121}
122
123impl Radians for f32 {
124    #[inline(always)]
125    fn _90() -> f32 {
126        ::std::f32::consts::FRAC_PI_2
127    }
128
129    #[inline(always)]
130    fn _180() -> f32 {
131        ::std::f32::consts::PI
132    }
133
134    #[inline(always)]
135    fn _360() -> f32 {
136        <Self as Radians>::_180() * 2.0
137    }
138
139    #[inline(always)]
140    fn deg_to_rad(self) -> Self {
141        self * (::std::f32::consts::PI / 180.0_f32)
142    }
143
144    #[inline(always)]
145    fn rad_to_deg(self) -> Self {
146        self * (180.0_f32 / ::std::f32::consts::PI)
147    }
148}
149
150impl Radians for f64 {
151    #[inline(always)]
152    fn _90() -> f64 {
153        ::std::f64::consts::FRAC_PI_2
154    }
155
156    #[inline(always)]
157    fn _180() -> f64 {
158        ::std::f64::consts::PI
159    }
160
161    #[inline(always)]
162    fn _360() -> f64 {
163        <Self as Radians>::_180() * 2.0
164    }
165
166    #[inline(always)]
167    fn deg_to_rad(self) -> Self {
168        self * (::std::f64::consts::PI / 180.0_f64)
169    }
170
171    #[inline(always)]
172    fn rad_to_deg(self) -> Self {
173        self * (180.0_f64 / ::std::f64::consts::PI)
174    }
175}
176
177/// Number 1.
178pub trait One {
179    /// Returns 1.
180    fn one() -> Self;
181}
182
183/// Number 0.
184pub trait Zero {
185    /// Returns 0.
186    fn zero() -> Self;
187}
188
189impl One for f32 {
190    #[inline(always)]
191    fn one() -> f32 { 1.0 }
192}
193
194impl One for f64 {
195    #[inline(always)]
196    fn one() -> f64 { 1.0 }
197}
198
199impl Zero for f32 {
200    #[inline(always)]
201    fn zero() -> f32 { 0.0 }
202}
203
204impl Zero for f64 {
205    #[inline(always)]
206    fn zero() -> f64 { 0.0 }
207}
208
209/// Square root.
210pub trait Sqrt {
211    /// Returns square root.
212    fn sqrt(self) -> Self;
213}
214
215impl Sqrt for f32 {
216    #[inline(always)]
217    fn sqrt(self) -> f32 { self.sqrt() }
218}
219
220impl Sqrt for f64 {
221    #[inline(always)]
222    fn sqrt(self) -> f64 { self.sqrt() }
223}
224
225/// Basic trigonometry functions
226pub trait Trig {
227    /// Returns sine of self.
228    fn sin(self) -> Self;
229    /// Returns cosine of self.
230    fn cos(self) -> Self;
231    /// Returns tangent of self.
232    fn tan(self) -> Self;
233    /// Returns inverse sine of self.
234    fn asin(self) -> Self;
235    /// Returns inverse cosine of self.
236    fn acos(self) -> Self;
237    /// Returns inverse tangent of self.
238    fn atan(self) -> Self;
239    /// Returns the four quadrant arctangent of self (y) and other (x).
240    fn atan2(self, other: Self) -> Self;
241    /// Returns hyperbolic sine of self.
242    fn sinh(self) -> Self;
243    /// Returns hyperbolic cosine of self.
244    fn cosh(self) -> Self;
245    /// Returns hyperbolic tangent of self.
246    fn tanh(self) -> Self;
247    /// Returns inverse hyperbolic sine of self.
248    fn asinh(self) -> Self;
249    /// Returns inverse hyperbolic cosine of self.
250    fn acosh(self) -> Self;
251    /// Returns inverse hyperbolic tangent of self.
252    fn atanh(self) -> Self;
253}
254
255impl Trig for f32 {
256    #[inline(always)]
257    fn sin(self) -> f32 { self.sin() }
258
259    #[inline(always)]
260    fn cos(self) -> f32 { self.cos() }
261
262    #[inline(always)]
263    fn tan(self) -> f32 { self.tan() }
264
265    #[inline(always)]
266    fn asin(self) -> f32 { self.asin() }
267
268    #[inline(always)]
269    fn acos(self) -> f32 { self.acos() }
270
271    #[inline(always)]
272    fn atan(self) -> f32 { self.atan() }
273
274    #[inline(always)]
275    fn atan2(self, other: f32) -> f32 { self.atan2(other) }
276
277    #[inline(always)]
278    fn sinh(self) -> f32 { self.sinh() }
279
280    #[inline(always)]
281    fn cosh(self) -> f32 { self.cosh() }
282
283    #[inline(always)]
284    fn tanh(self) -> f32 { self.tanh() }
285
286    #[inline(always)]
287    fn asinh(self) -> f32 { self.asinh() }
288
289    #[inline(always)]
290    fn acosh(self) -> f32 { self.acosh() }
291
292    #[inline(always)]
293    fn atanh(self) -> f32 { self.atanh() }
294}
295
296impl Trig for f64 {
297    #[inline(always)]
298    fn sin(self) -> f64 { self.sin() }
299
300    #[inline(always)]
301    fn cos(self) -> f64 { self.cos() }
302
303    #[inline(always)]
304    fn tan(self) -> f64 { self.tan() }
305
306    #[inline(always)]
307    fn asin(self) -> f64 { self.asin() }
308
309    #[inline(always)]
310    fn acos(self) -> f64 { self.acos() }
311
312    #[inline(always)]
313    fn atan(self) -> f64 { self.atan() }
314
315    #[inline(always)]
316    fn atan2(self, other: f64) -> f64 { self.atan2(other) }
317
318    #[inline(always)]
319    fn sinh(self) -> f64 { self.sinh() }
320
321    #[inline(always)]
322    fn cosh(self) -> f64 { self.cosh() }
323
324    #[inline(always)]
325    fn tanh(self) -> f64 { self.tanh() }
326
327    #[inline(always)]
328    fn asinh(self) -> f64 { self.asinh() }
329
330    #[inline(always)]
331    fn acosh(self) -> f64 { self.acosh() }
332
333    #[inline(always)]
334    fn atanh(self) -> f64 { self.atanh() }
335}
336
337/// Casts into another type.
338pub trait Cast<T> {
339    /// Casts into other type.
340    fn cast(self) -> T;
341}
342
343impl Cast<f32> for f64 {
344    #[inline(always)]
345    fn cast(self) -> f32 { self as f32 }
346}
347
348impl Cast<f64> for f32 {
349    #[inline(always)]
350    fn cast(self) -> f64 { self as f64 }
351}
352
353impl Cast<f32> for f32 {
354    #[inline(always)]
355    fn cast(self) -> f32 { self }
356}
357
358impl Cast<f64> for f64 {
359    #[inline(always)]
360    fn cast(self) -> f64 { self }
361}
362
363/// Trait for converting from different numeric types
364pub trait FromPrimitive {
365    /// from a f64
366    fn from_f64(t: f64) -> Self;
367    /// from a f32
368    fn from_f32(t: f32) -> Self;
369    /// from a isze
370    fn from_isize(t: isize) -> Self;
371    /// from a u32
372    fn from_u32(t: u32) -> Self;
373    /// from a i32
374    fn from_i32(t: i32) -> Self;
375    // Add more as needed..
376}
377
378impl FromPrimitive for f64 {
379    #[inline(always)]
380    fn from_f64(t: f64) -> Self { t }
381    #[inline(always)]
382    fn from_f32(t: f32) -> Self { t as f64 }
383    #[inline(always)]
384    fn from_isize(t: isize) -> Self { t as f64 }
385    #[inline(always)]
386    fn from_u32(t: u32) -> Self { t as f64 }
387    #[inline(always)]
388    fn from_i32(t: i32) -> Self { t as f64 }
389}
390
391impl FromPrimitive for f32 {
392    #[inline(always)]
393    fn from_f64(t: f64) -> Self { t as f32 }
394    #[inline(always)]
395    fn from_f32(t: f32) -> Self { t }
396    #[inline(always)]
397    fn from_isize(t: isize) -> Self { t as f32 }
398    #[inline(always)]
399    fn from_u32(t: u32) -> Self { t as f32 }
400    #[inline(always)]
401    fn from_i32(t: i32) -> Self { t as f32 }
402}
403
404#[cfg(test)]
405mod test {
406    use super::*;
407
408    #[test]
409    fn test_f32_sqrt() {
410        let a = 4.0_f32;
411        let b = <f32 as Sqrt>::sqrt(a);
412        assert!((b - 2.0_f32).abs() < f32::EPSILON)
413    }
414
415    #[test]
416    fn test_f64_sqrt() {
417        let a = 4.0_f64;
418        let b = <f64 as Sqrt>::sqrt(a);
419        assert!((b - 2.0_f64).abs() < f64::EPSILON)
420    }
421
422    #[test]
423    fn test_f32_deg_to_rad() {
424        let degrees = 23.0_f32;
425        let radians = degrees.deg_to_rad();
426        assert!((radians - 0.401_425).abs() > f32::EPSILON);
427    }
428
429    #[test]
430    fn test_f64_deg_to_rad() {
431        let degrees = 60.0_f64;
432        let radians = degrees.deg_to_rad();
433        assert!((radians - std::f64::consts::FRAC_PI_3).abs()  == f64::EPSILON);
434    }
435}