Skip to main content

grafix_toolbox/kit/policies/math/
math_ext.rs

1pub use ops::Neg;
2
3trait_alias!(
4	pub Number,
5	Cast<i32>
6		+ ops::Add<Output = Self>
7		+ ops::Mul<Output = Self>
8		+ ops::Div<Output = Self>
9		+ EucMod<Self>
10		+ Pow<Self>
11		+ Precise
12		+ Round
13);
14
15pub trait EpsEq: Copy + PartialOrd + ops::Sub<Output = Self> {
16	#[inline(always)]
17	fn eps_eq(self, r: Self) -> bool {
18		self == r
19	}
20	#[inline(always)]
21	fn trsh_eq(self, r: Self, t: Self) -> bool {
22		let d = if self >= r { self - r } else { r - self };
23		d < t || d.eps_eq(t)
24	}
25}
26impl_trait_for!(EpsEq = u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
27macro_rules! impl_eps_eq {
28	($(($t: ty, $i: ty, $b: literal)),+) => {
29		$(impl EpsEq for $t {
30			#[inline(always)]
31			fn eps_eq(self, r: Self) -> bool {
32				let (l, o) = (self, Self::default());
33
34				if l == r {
35					return true;
36				}
37
38				if l == o || r == o {
39					return (l - r).abs() <= Self::EPSILON * Self::to($b);
40				}
41
42				if (l < o) != (r < o) {
43					return false;
44				}
45
46				let (l, r) = (Self::to_bits(l) << 1 >> 1, Self::to_bits(r) << 1 >> 1);
47				unsafe { (l as $i).unchecked_sub(r as $i) }.abs() <= $b
48			}
49		})+
50	}
51}
52impl_eps_eq!((f16, i16, 2), (f32, i32, 4), (f64, i64, 8));
53
54pub trait Precise: EpsEq + Default {
55	fn mix(self, r: Self, a: f32) -> Self;
56	fn root(self) -> Self;
57	#[inline(always)]
58	fn is_zero(&self) -> bool {
59		self.eps_eq(<_>::default())
60	}
61}
62macro_rules! impl_sqrt {
63	($($t: ty),+) => {
64		$(impl Precise for $t {
65			#[inline(always)]
66			fn mix(self, r: Self, a: f32) -> Self {
67				Self::to(f32(self) * (1. - a) + f32(r) * a)
68			}
69			#[inline(always)]
70			fn root(self) -> Self {
71				Self::to(f32(self).sqrt())
72			}
73		})+
74	}
75}
76impl_sqrt!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f16, f32, usize, isize);
77impl Precise for f64 {
78	#[inline(always)]
79	fn mix(self, r: Self, a: f32) -> Self {
80		let a = f64(a);
81		self * (1. - a) + r * a
82	}
83	#[inline(always)]
84	fn root(self) -> Self {
85		self.sqrt()
86	}
87}
88
89pub trait Round: Sized {
90	#[inline(always)]
91	fn round(self) -> Self {
92		self
93	}
94	#[inline(always)]
95	fn abs(self) -> Self {
96		self
97	}
98}
99impl_trait_for!(Round = u8, u16, u32, u64, u128, usize);
100macro_rules! impl_abs {
101	($($t: ty),+) => {
102		$(impl Round for $t {
103			#[inline(always)]
104			fn abs(self) -> Self {
105				self.abs()
106			}
107		})+
108	}
109}
110impl_abs!(i8, i16, i32, i64, i128, isize);
111impl Round for f16 {
112	#[inline(always)]
113	fn round(self) -> Self {
114		f16(f32(self).round())
115	}
116	#[inline(always)]
117	fn abs(self) -> Self {
118		f16(f32(self).abs())
119	}
120}
121macro_rules! impl_abs_f {
122	($($t: ty),+) => {
123		$(impl Round for $t {
124			#[inline(always)]
125			fn round(self) -> Self {
126				self.round()
127			}
128			#[inline(always)]
129			fn abs(self) -> Self {
130				self.abs()
131			}
132		})+
133	}
134}
135impl_abs_f!(f32, f64);
136
137pub trait Pow<T> {
138	fn power(self, _: T) -> Self;
139}
140macro_rules! impl_pow {
141	($($t: ty),+) => {
142		$(impl<T> Pow<T> for $t
143		where
144			u32: Cast<T>,
145		{
146			#[inline(always)]
147			fn power(self, r: T) -> Self {
148				self.pow(u32(r))
149			}
150		})+
151	}
152}
153impl_pow!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
154impl<T> Pow<T> for f16
155where
156	i32: Cast<T>,
157{
158	#[inline(always)]
159	fn power(self, r: T) -> Self {
160		f16(f32(self).powi(i32(r)))
161	}
162}
163macro_rules! impl_powi {
164	($($t: ty),+) => {
165		$(impl<T> Pow<T> for $t
166		where
167			i32: Cast<T>,
168		{
169			#[inline(always)]
170			fn power(self, r: T) -> Self {
171				self.powi(i32(r))
172			}
173		})+
174	}
175}
176impl_powi!(f32, f64);
177
178pub trait EucMod<T> {
179	fn euc_mod(self, _: T) -> Self;
180}
181macro_rules! impl_euc_mod {
182	($($t: ty),+) => {
183		$(impl<T> EucMod<T> for $t
184		where
185			Self: Cast<T>,
186		{
187			#[inline(always)]
188			fn euc_mod(self, r: T) -> Self {
189				self.rem_euclid(Self::to(r))
190			}
191		})+
192	}
193}
194impl_euc_mod!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, usize, isize);
195impl<T> EucMod<T> for f16
196where
197	f32: Cast<T>,
198{
199	#[inline(always)]
200	fn euc_mod(self, r: T) -> Self {
201		f16(self.to_f32().rem_euclid(f32(r)))
202	}
203}
204
205use {super::pre::*, std::ops};