Skip to main content

maths_rs/
num.rs

1use std::ops::Mul;
2use std::ops::MulAssign;
3use std::ops::Add;
4use std::ops::AddAssign;
5use std::ops::Sub;
6use std::ops::SubAssign;
7use std::ops::Div;
8use std::ops::DivAssign;
9use std::ops::Rem;
10use std::ops::RemAssign;
11use std::ops::Neg;
12use std::ops::Shl;
13use std::ops::ShlAssign;
14use std::ops::Shr;
15use std::ops::ShrAssign;
16use std::ops::BitOr;
17use std::ops::BitOrAssign;
18use std::ops::BitAnd;
19use std::ops::BitAndAssign;
20use std::ops::BitXor;
21use std::ops::BitXorAssign;
22
23use std::cmp::PartialEq;
24use std::cmp::PartialOrd;
25
26use std::fmt::Display;
27
28/// base trait for scalar and vector numerical operations, arithmetic and generic constants
29pub trait Base<T: Number>:
30    Copy + Display +
31    Add<Output=Self> + AddAssign +
32    Sub<Output=Self> + SubAssign +
33    Mul<Output=Self> + MulAssign +
34    Div<Output=Self> + DivAssign +
35    Rem<Output=Self> + RemAssign
36    where Self: Sized {
37    /// returns `0`
38    fn zero() -> Self;
39    /// returns `1`
40    fn one() -> Self;
41    /// returns `2`
42    fn two() -> Self;
43    /// returns `3`
44    fn three() -> Self;
45    /// returns `4`
46    fn four() -> Self;
47    /// returns the smallest representable number with the available precision
48    fn min_value() -> Self;
49    /// returns the largest representable number with the available precision
50    fn max_value() -> Self;
51}
52
53/// operations applicable to both floating point, integer and unsigned types
54pub trait NumberOps<T: Number> {
55    /// returns the minimum value of `a` and `b`
56    fn min(a: Self, b: Self) -> Self;
57    /// returns the maximum value of `a` and `b`
58    fn max(a: Self, b: Self) -> Self;
59    /// returns value `x` clamped to the range `min` - `max`
60    fn clamp(x: Self, min: Self, max: Self) -> Self;
61    /// returns a vector stepped component wise; `1` if `a` is >= `b`, `0` otherwise
62    fn step(a: Self, b: Self) -> Self;
63}
64
65/// operations applicable to signed types
66pub trait SignedNumberOps<T: SignedNumber>: Neg<Output=Self> {
67    /// returns sign value of `a`; `-1` = negative, `1` = positive or `0` (integers only)
68    fn signum(a: Self) -> Self;
69    /// returns the absolute (postive) value of `a`
70    fn abs(a: Self) -> Self;
71}
72
73/// operations applicable to integer types
74pub trait IntegerOps<T: Integer> {
75    /// returns value `a` raised to unsigned integer power `exp`
76    fn pow(a: Self, exp: u32) -> Self;
77}
78
79/// trait for performing linear interpolation on scalars, vectors or quaternions
80pub trait Lerp<T: Float> {
81    /// returns linear interpolation of `t` between `e0` and `e1`, `t` specifies the ratio to interpolate between the values
82    fn lerp(e0: Self, e1: Self, t: T) -> Self;
83}
84
85pub trait Cast<T: Number> where Self: Sized {
86    fn from_f32(v: f32) -> Self;
87    fn from_f64(v: f64) -> Self;
88    fn from_u32(v: u32) -> Self;
89    fn from_i32(v: i32) -> Self;
90    fn from_u64(v: u64) -> Self;
91    fn from_i64(v: i64) -> Self;
92    fn from_usize(v: usize) -> Self;
93    fn as_f32(&self) -> f32;
94    fn as_f64(&self) -> f64;
95    fn as_u32(&self) -> u32;
96    fn as_i32(&self) -> i32;
97    fn as_u64(&self) -> u64;
98    fn as_i64(&self) -> i64;
99    fn as_usize(&self) -> usize;
100}
101
102/// operations applicable to floating point types
103pub trait FloatOps<T: Float>: Lerp<T> where Self: Sized {
104    /// returns `0.5`
105    fn point_five() -> Self;
106    /// returns `pi`
107    fn pi() -> Self;
108    /// returns `2.0 * pi`
109    fn two_pi() -> Self;
110    /// returns `1.0 / pi`
111    fn inv_pi() -> Self;
112    /// returns `phi` (the golden constant)
113    fn phi() -> Self;
114    /// returns `1.0 / phi` inverse phi (the golden constant)
115    fn inv_phi() -> Self;
116    /// returns tau, which is ratio of the circumference of a circle to its radius
117    fn tau() -> Self;
118    /// returns square root of `a`
119    fn sqrt(a: Self) -> Self;
120    /// returns reciprocal square root of `a` (`1/sqrt(a)`)
121    fn rsqrt(a: Self) -> Self;
122    /// returns the reciprocal of `a`
123    fn recip(a: Self) -> Self;
124    /// returns `a` raised to integer power `exp`
125    fn powi(a: Self, exp: i32) -> Self;
126    /// returns `a` raised to float power `exp`
127    fn powf(a: Self, exp: T) -> Self;
128    /// returns fused multiply add `a * m + b`
129    fn mad(m: Self, a: Self, b: Self) -> Self;
130    /// returns true if `a` and `b` are approximately equal within the designated epsilon `eps`
131    fn approx(a: Self, b: Self, eps: T) -> bool;
132    /// returns the greatest integer which is less than or equal to a
133    fn floor(a: Self) -> Self;
134    /// returns the smallest integer which is greater than or equal to `a`
135    fn ceil(a: Self) -> Self;
136    /// returns value `a` with the same sign as the second parameter `sign`
137    fn copysign(a: Self, sign: T) -> Self;
138    /// returns hermite interpolation between `0-1` of `t` between edges `e0` and `e1`
139    fn smoothstep(e0: Self, e1: Self, t: T) -> Self;
140    /// returns `a` rounded component wise
141    fn round(a: Self) -> Self;
142    /// returns true if `a` is not a number (`nan`)
143    fn is_nan(a: Self) -> Self;
144    /// returns true if `a` is `inf`
145    fn is_infinite(a: Self) -> Self;
146    /// returns true is `a` is finite
147    fn is_finite(a: Self) -> Self;
148    /// returns the value of `a` saturated (clamped between `0-1`). equivalent to `clamp(x, 0, 1)`
149    fn saturate(x: Self) -> Self;
150    /// returns `theta` converted from degrees to radians
151    fn deg_to_rad(theta: Self) -> Self;
152    /// returns `theta` converted from radians to degrees
153    fn rad_to_deg(theta: Self) -> Self;
154    /// returns the floating-point remainder of `x/y`
155    fn fmod(x: Self, y: Self) -> Self;
156    /// returns the fractional part of floating point number `v` removing the integer part
157    fn frac(v: Self) -> Self;
158    /// returns the integer part of float value `v` truncating the decimal part
159    fn trunc(v: Self) -> Self;
160    /// returns a tuple containing `(frac(v), trunc(v))` breaking the float into 2 parts
161    fn modf(v: Self) -> (Self, Self);
162    /// returns the cosine of `v` where the value `v` is in radians
163    fn cos(v: Self) -> Self;
164    /// returns the sine of `v` where the value `v` is in radians
165    fn sin(v: Self) -> Self;
166    /// returns the tangent of `v` where the value `v` is in radians
167    fn tan(v: Self) -> Self;
168    /// returns the arc cosine of `v` where the value `v` is in radians
169    fn acos(v: Self) -> Self;
170    /// returns the arc sine of `v` where the value `v` is in radians
171    fn asin(v: Self) -> Self;
172    /// returns the arc tangent of `v` where the value `v` is in radians
173    fn atan(v: Self) -> Self;
174    /// returns the hyperbolic cosine of `v` where the value `v` is in radians
175    fn cosh(v: Self) -> Self;
176    /// returns the hyperbolic sine of `v` where the value `v` is in radians
177    fn sinh(v: Self) -> Self;
178    /// returns the hyperbolic tangent of `v` where the value `v` is in radians
179    fn tanh(v: Self) -> Self;
180    /// returns a tuple of `(sin(v), cos(v))` of `v` where the value `v` is in radians
181    fn sin_cos(v: Self) -> (Self, Self);
182    // returns the value of the arc tangent of `y/x`, expressed in radians
183    fn atan2(y: Self, x: Self) -> Self;
184    // returns the base-e exponential function of `v`, which is `e` raised to the power `v`
185    fn exp(v: Self) -> Self;
186    /// returns 2 raised to the given power `v`
187    fn exp2(v: Self) -> Self;
188    /// returns the binary (base-2) logarithm of `v`
189    fn log2(v: Self) -> Self;
190    /// returns the common (base-10) logarithm of `v`
191    fn log10(v: Self) -> Self;
192    /// returns the logarithm of `v` in base
193    fn log(v: Self, base: T) -> Self;
194}
195
196macro_rules! number_trait_impl {
197    ($($func:ident),*) => {
198        /// base number trait for signed or unsigned, floating point or integer numbers.
199        pub trait Number: Base<Self> + Default + PartialEq + PartialOrd  {}
200        number_impl!(f64 { $($func),* }, 0.0, 1.0);
201        number_impl!(f32 { $($func),* }, 0.0, 1.0);
202        number_impl!(usize { $($func),* }, 0, 1);
203        number_impl!(isize { $($func),* }, 0, 1);
204        number_impl!(i64 { $($func),* }, 0, 1);
205        number_impl!(u64 { $($func),* }, 0, 1);
206        number_impl!(i32 { $($func),* }, 0, 1);
207        number_impl!(u32 { $($func),* }, 0, 1);
208        number_impl!(i16 { $($func),* }, 0, 1);
209        number_impl!(u16 { $($func),* }, 0, 1);
210        number_impl!(i8 { $($func),* }, 0, 1);
211        number_impl!(u8 { $($func),* }, 0, 1);
212    }
213}
214
215macro_rules! number_impl {
216    ($t:ident { $($func:ident),* }, $zero:literal, $one:literal) => {
217        impl Base<$t> for $t {
218            fn min_value() -> Self {
219                $t::MIN
220            }
221
222            fn max_value() -> Self {
223                $t::MAX
224            }
225
226            fn zero() -> Self {
227                $zero
228            }
229
230            fn one() -> Self {
231                $one
232            }
233
234            fn two() -> Self {
235                2 as Self
236            }
237
238            fn three() -> Self {
239                3 as Self
240            }
241
242            fn four() -> Self {
243                4 as Self
244            }
245
246        }
247
248        impl Number for $t {}
249
250        impl NumberOps<$t> for $t {
251            fn min(a: Self, b: Self) -> Self {
252                a.min(b)
253            }
254
255            fn max(a: Self, b: Self) -> Self {
256                a.max(b)
257            }
258
259            fn clamp(x: Self, min: Self, max: Self) -> Self {
260                NumberOps::max(NumberOps::min(x, max), min)
261            }
262
263            fn step(a: Self, b: Self) -> Self {
264                if a >= b {
265                    Self::one()
266                }
267                else {
268                    Self::zero()
269                }
270            }
271        }
272
273        impl Cast<$t> for $t {
274            fn from_f32(v: f32) -> Self {
275                v as Self
276            }
277
278            fn from_f64(v: f64) -> Self {
279                v as Self
280            }
281
282            fn from_u32(v: u32) -> Self {
283                v as Self
284            }
285
286            fn from_i32(v: i32) -> Self {
287                v as Self
288            }
289
290            fn from_u64(v: u64) -> Self {
291                v as Self
292            }
293
294            fn from_i64(v: i64) -> Self {
295                v as Self
296            }
297
298            fn from_usize(v: usize) -> Self {
299                v as Self
300            }
301
302            fn as_f32(&self) -> f32 {
303                *self as f32
304            }
305
306            fn as_f64(&self) -> f64 {
307                *self as f64
308            }
309
310            fn as_u32(&self) -> u32 {
311                *self as u32
312            }
313
314            fn as_i32(&self) -> i32 {
315                *self as i32
316            }
317
318            fn as_u64(&self) -> u64 {
319                *self as u64
320            }
321
322            fn as_i64(&self) -> i64 {
323                *self as i64
324            }
325
326            fn as_usize(&self) -> usize {
327                *self as usize
328            }
329        }
330    }
331}
332
333macro_rules! signed_number_trait_impl {
334    ($($func:ident),*) => {
335        /// signed number trait for signed integers or floats.
336        pub trait SignedNumber: Number + Neg<Output=Self> {
337            fn minus_one() -> Self;
338        }
339        signed_number_impl!(f64 { $($func),* }, -1.0);
340        signed_number_impl!(f32 { $($func),* }, -1.0);
341        signed_number_impl!(isize { $($func),* }, -1);
342        signed_number_impl!(i64 { $($func),* }, -1);
343        signed_number_impl!(i32 { $($func),* }, -1);
344        signed_number_impl!(i16 { $($func),* }, -1);
345        signed_number_impl!(i8 { $($func),* }, -1);
346    }
347}
348
349macro_rules! signed_number_impl {
350    ($t:ident { $($func:ident),* }, $minus_one:literal) => {
351        impl SignedNumber for $t {
352            fn minus_one() -> Self {
353                $minus_one
354            }
355        }
356
357        impl SignedNumberOps<$t> for $t {
358            $(
359                fn $func(v: Self) -> Self {
360                    v.$func()
361                }
362            )*
363        }
364    }
365}
366
367macro_rules! float_trait_impl {
368    ($($func:ident),*) => {
369        /// floating point trait for various levels of fp precision
370        pub trait Float: SignedNumber {
371            fn small_epsilon() -> Self;
372        }
373        float_impl!(f64 { $($func),* });
374        float_impl!(f32 { $($func),* });
375    }
376}
377
378macro_rules! float_impl {
379    ($t:ident { $($func:ident),* } ) => {
380        impl Float for $t {
381            fn small_epsilon() -> Self {
382                1e-30
383            }
384        }
385
386        impl Lerp<$t> for $t {
387            fn lerp(e0: Self, e1: Self, t: Self) -> Self {
388                e0 + t * (e1 - e0)
389            }
390        }
391
392        impl FloatOps<$t> for $t {
393            $(
394                fn $func(v: Self) -> Self {
395                    v.$func()
396                }
397            )*
398
399            fn point_five() -> Self {
400                0.5 as Self
401            }
402
403            #[allow(clippy::excessive_precision)]
404            fn pi() -> Self {
405                3.14159265358979323846264338327950288 as Self
406            }
407
408            fn two_pi() -> Self {
409                2.0 as Self * Self::pi() as Self
410            }
411
412            fn inv_pi() -> Self {
413                1.0 as Self / Self::pi() as Self
414            }
415
416            #[allow(clippy::excessive_precision)]
417            fn phi() -> Self {
418                1.618033988749894 as Self
419            }
420
421            fn inv_phi() -> Self {
422                1.0 as Self / Self::phi() as Self
423            }
424
425            #[allow(clippy::excessive_precision)]
426            fn tau() -> Self {
427                6.2831853071795864 as Self
428            }
429
430            fn rsqrt(a: Self) -> Self {
431                Self::one()/Self::sqrt(a)
432            }
433
434            fn approx(a: Self, b: Self, eps: Self) -> bool {
435                Self::abs(a - b) < eps
436            }
437
438            fn mad(m: Self, a: Self, b: Self) -> Self {
439                m.mul_add(a, b)
440            }
441
442            fn is_nan(v: Self) -> $t {
443                if v.is_nan() { $t::one() } else { $t::zero() }
444            }
445
446            fn is_infinite(v: Self) -> $t {
447                if v.is_infinite() { $t::one() } else { $t::zero() }
448            }
449
450            fn is_finite(v: Self) -> $t {
451                if v.is_finite() { $t::one() } else { $t::zero() }
452            }
453
454            fn copysign(a: Self, sign: $t) -> Self {
455                a.copysign(sign)
456            }
457
458            fn smoothstep(e0: Self, e1: Self, t: Self) -> Self {
459                if t < e0 { return Self::zero(); }
460                if (t >= e1) { return Self::one(); }
461                let x = (t - e0) / (e1 - e0);
462                x * x * (3 as Self - 2 as Self * x)
463            }
464
465            fn saturate(v: Self) -> Self {
466                Self::max(Self::min(v, 1.0), 0.0)
467            }
468
469            fn powi(v: Self, exp: i32) -> Self {
470                v.powi(exp)
471            }
472
473            fn powf(v: Self, exp: $t) -> Self {
474                v.powf(exp)
475            }
476
477            fn fmod(x: Self, y: Self) -> Self {
478                x % y
479            }
480
481            fn frac(v: Self) -> Self {
482                v.fract()
483            }
484
485            fn trunc(v: Self) -> Self {
486                v.trunc()
487            }
488
489            fn modf(v: Self) -> (Self, Self) {
490                (Self::frac(v), Self::trunc(v))
491            }
492
493            fn log(v: Self, base: Self) -> Self {
494                v.log(base)
495            }
496
497            fn sin_cos(v: Self) -> (Self, Self) {
498                (v.sin(), v.cos())
499            }
500
501            fn atan2(y: Self, x: Self) -> Self {
502                y.atan2(x)
503            }
504
505            fn deg_to_rad(theta: Self) -> Self {
506                theta.to_radians()
507            }
508
509            fn rad_to_deg(theta: Self) -> Self {
510                theta.to_degrees()
511            }
512        }
513    }
514}
515
516macro_rules! integer_trait_impl {
517    ($($func:ident),*) => {
518        /// integer point trait for various sized integers
519        pub trait Integer: Number +
520            Shl<Output=Self> + ShlAssign +
521            Shr<Output=Self> + ShrAssign +
522            BitOr<Output=Self> + BitOrAssign +
523            BitAnd<Output=Self> + BitAndAssign +
524            BitXor<Output=Self> + BitXorAssign {
525        }
526        integer_impl!(i8 { $($func),* });
527        integer_impl!(u8 { $($func),* });
528        integer_impl!(i16 { $($func),* });
529        integer_impl!(u16 { $($func),* });
530        integer_impl!(i32 { $($func),* });
531        integer_impl!(u32 { $($func),* });
532        integer_impl!(i64 { $($func),* });
533        integer_impl!(u64 { $($func),* });
534    }
535}
536
537macro_rules! integer_impl {
538    ($t:ident { $($func:ident),* } ) => {
539        impl Integer for $t {
540        }
541
542        impl IntegerOps<$t> for $t {
543            fn pow(v: Self, exp: u32) -> Self {
544                v.pow(exp)
545            }
546        }
547    }
548}
549
550number_trait_impl!();
551integer_trait_impl!();
552
553signed_number_trait_impl!(signum, abs);
554float_trait_impl!(
555    floor, ceil, round, sqrt, recip,
556    cos, sin, tan, acos, asin, atan, cosh, sinh, tanh,
557    exp, exp2, log2, log10
558);