1use core::fmt::Debug;
28use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
29
30pub trait Num:
32 Copy + PartialEq + Debug + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
33{
34 fn zero() -> Self;
36 fn one() -> Self;
38 fn from_i64(v: i64) -> Self;
40}
41
42pub trait Signed: Num + Neg<Output = Self> + PartialOrd {
44 fn abs(self) -> Self;
46 fn signum(self) -> Self;
48 fn is_negative(self) -> bool;
50}
51
52pub trait Field: Num + Div<Output = Self> + Rem<Output = Self> {
54 fn div(self, other: Self) -> Self;
56 fn reciprocal(self) -> Self;
58}
59
60pub trait Real: Num + Signed + Div<Output = Self> + Rem<Output = Self> + PartialOrd {
65 fn from_f64(v: f64) -> Self;
67 fn to_f64(self) -> f64;
69
70 fn sqrt(self) -> Self;
72 fn cbrt(self) -> Self;
74 fn powf(self, e: Self) -> Self;
76 fn powi(self, e: i32) -> Self;
78 fn exp(self) -> Self;
80 fn exp_m1(self) -> Self;
82 fn ln(self) -> Self;
84 fn ln_1p(self) -> Self;
86 fn log(self, base: Self) -> Self;
88 fn log10(self) -> Self;
90 fn log2(self) -> Self;
92
93 fn sin(self) -> Self;
95 fn cos(self) -> Self;
97 fn tan(self) -> Self;
99 fn asin(self) -> Self;
101 fn acos(self) -> Self;
103 fn atan(self) -> Self;
105 fn atan2(self, other: Self) -> Self;
107
108 fn sinh(self) -> Self;
110 fn cosh(self) -> Self;
112 fn tanh(self) -> Self;
114 fn asinh(self) -> Self;
116 fn acosh(self) -> Self;
118 fn atanh(self) -> Self;
120
121 fn sin_cos(self) -> (Self, Self);
123 fn hypot(self, other: Self) -> Self;
125 fn copysign(self, other: Self) -> Self;
127 fn abs_sub(self, other: Self) -> Self;
129 fn recip(self) -> Self;
131
132 fn floor(self) -> Self;
134 fn ceil(self) -> Self;
136 fn round(self) -> Self;
138 fn trunc(self) -> Self;
140 fn fract(self) -> Self;
142
143 fn min(self, other: Self) -> Self;
145 fn max(self, other: Self) -> Self;
147
148 fn is_finite(self) -> bool;
150 fn is_nan(self) -> bool;
152 fn is_infinite(self) -> bool;
154 fn is_normal(self) -> bool;
156 fn is_subnormal(self) -> bool;
158 fn is_sign_negative(self) -> bool;
160 fn is_sign_positive(self) -> bool;
162
163 fn signum(self) -> Self;
165}
166
167pub trait Normed: Signed {
171 fn norm(self) -> Self;
173}
174
175macro_rules! impl_num_int {
176 ($($t:ty),* $(,)?) => {$(
177 impl Num for $t {
178 fn zero() -> Self { 0 }
179 fn one() -> Self { 1 }
180 fn from_i64(v: i64) -> Self { v as $t }
181 }
182 )*};
183}
184impl_num_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
185
186macro_rules! impl_num_float {
187 ($($t:ty),* $(,)?) => {$(
188 impl Num for $t {
189 fn zero() -> Self { 0.0 }
190 fn one() -> Self { 1.0 }
191 fn from_i64(v: i64) -> Self { v as $t }
192 }
193 )*};
194}
195impl_num_float!(f32, f64);
196
197macro_rules! impl_signed_int {
198 ($($t:ty),* $(,)?) => {$(
199 impl Signed for $t {
200 fn abs(self) -> Self { self.abs() }
201 fn signum(self) -> Self { self.signum() }
202 fn is_negative(self) -> bool { self < 0 }
203 }
204 )*};
205}
206impl_signed_int!(i8, i16, i32, i64, isize);
207
208macro_rules! impl_signed_float {
209 ($($t:ty),* $(,)?) => {$(
210 impl Signed for $t {
211 fn abs(self) -> Self { self.abs() }
212 fn signum(self) -> Self { self.signum() }
213 fn is_negative(self) -> bool { self.is_sign_negative() }
214 }
215 )*};
216}
217impl_signed_float!(f32, f64);
218
219macro_rules! impl_field_float {
220 ($($t:ty),* $(,)?) => {$(
221 impl Field for $t {
222 fn div(self, other: Self) -> Self { self / other }
223 fn reciprocal(self) -> Self { 1.0 / self }
224 }
225 )*};
226}
227impl_field_float!(f32, f64);
228
229macro_rules! impl_real {
230 ($($t:ty),* $(,)?) => {$(
231 impl Real for $t {
232 fn from_f64(v: f64) -> Self { v as $t }
233 fn to_f64(self) -> f64 { f64::from(self) }
234 fn sqrt(self) -> Self { self.sqrt() }
235 fn cbrt(self) -> Self { self.cbrt() }
236 fn powf(self, e: Self) -> Self { self.powf(e) }
237 fn powi(self, e: i32) -> Self { self.powi(e) }
238 fn exp(self) -> Self { self.exp() }
239 fn exp_m1(self) -> Self { self.exp_m1() }
240 fn ln(self) -> Self { self.ln() }
241 fn ln_1p(self) -> Self { self.ln_1p() }
242 fn log(self, base: Self) -> Self { self.log(base) }
243 fn log10(self) -> Self { self.log10() }
244 fn log2(self) -> Self { self.log2() }
245 fn sin(self) -> Self { self.sin() }
246 fn cos(self) -> Self { self.cos() }
247 fn tan(self) -> Self { self.tan() }
248 fn asin(self) -> Self { self.asin() }
249 fn acos(self) -> Self { self.acos() }
250 fn atan(self) -> Self { self.atan() }
251 fn atan2(self, other: Self) -> Self { self.atan2(other) }
252 fn sinh(self) -> Self { self.sinh() }
253 fn cosh(self) -> Self { self.cosh() }
254 fn tanh(self) -> Self { self.tanh() }
255 fn asinh(self) -> Self { self.asinh() }
256 fn acosh(self) -> Self { self.acosh() }
257 fn atanh(self) -> Self { self.atanh() }
258 fn sin_cos(self) -> (Self, Self) { self.sin_cos() }
259 fn hypot(self, other: Self) -> Self { self.hypot(other) }
260 fn copysign(self, other: Self) -> Self { self.copysign(other) }
261 fn abs_sub(self, other: Self) -> Self { (self - other).max(Self::zero()) }
262 fn recip(self) -> Self { self.recip() }
263 fn floor(self) -> Self { self.floor() }
264 fn ceil(self) -> Self { self.ceil() }
265 fn round(self) -> Self { self.round() }
266 fn trunc(self) -> Self { self.trunc() }
267 fn fract(self) -> Self { self.fract() }
268 fn min(self, other: Self) -> Self { self.min(other) }
269 fn max(self, other: Self) -> Self { self.max(other) }
270 fn is_finite(self) -> bool { self.is_finite() }
271 fn is_nan(self) -> bool { self.is_nan() }
272 fn is_infinite(self) -> bool { self.is_infinite() }
273 fn is_normal(self) -> bool { self.is_normal() }
274 fn is_subnormal(self) -> bool { self.is_subnormal() }
275 fn is_sign_negative(self) -> bool { self.is_sign_negative() }
276 fn is_sign_positive(self) -> bool { self.is_sign_positive() }
277 fn signum(self) -> Self { self.signum() }
278 }
279 )*};
280}
281impl_real!(f32, f64);
282
283impl Normed for f32 {
284 fn norm(self) -> Self {
285 self.abs()
286 }
287}
288impl Normed for f64 {
289 fn norm(self) -> Self {
290 self.abs()
291 }
292}
293impl Normed for i8 {
294 fn norm(self) -> Self {
295 self.abs()
296 }
297}
298impl Normed for i16 {
299 fn norm(self) -> Self {
300 self.abs()
301 }
302}
303impl Normed for i32 {
304 fn norm(self) -> Self {
305 self.abs()
306 }
307}
308impl Normed for i64 {
309 fn norm(self) -> Self {
310 self.abs()
311 }
312}
313impl Normed for isize {
314 fn norm(self) -> Self {
315 self.abs()
316 }
317}
318
319#[cfg(test)]
320#[allow(clippy::suboptimal_flops, clippy::imprecise_flops)]
321mod tests {
322 use super::*;
323
324 #[test]
325 fn identity_laws() {
326 for a in 0..100i64 {
327 assert_eq!(a + <i64 as Num>::zero(), a);
328 assert_eq!(a * <i64 as Num>::one(), a);
329 }
330 }
331
332 #[test]
333 fn signed_abs() {
334 assert_eq!((-5i32).abs(), 5);
335 assert_eq!((-2.5f64).abs(), 2.5);
336 assert_eq!((-2.5f64).signum(), -1.0);
337 }
338
339 #[test]
340 fn real_ops() {
341 let x = 9.0f64;
342 assert_eq!(x.sqrt(), 3.0);
343 assert_eq!(x.cbrt(), 2.080083823051904);
344 assert_eq!(x.powi(2), 81.0);
345 assert_eq!(x.powf(0.5), 3.0);
346 assert_eq!(x.ln(), 2.0 * 3.0f64.ln());
347 assert!((1.0f64.sin().powi(2) + 1.0f64.cos().powi(2) - 1.0).abs() < 1e-12);
348 assert!((0.5f64.asin() - 0.5f64.asin()).abs() < 1e-12);
349 assert!((0.5f64.acos() - 0.5f64.acos()).abs() < 1e-12);
350 assert!((1.0f64.atan() - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
351 assert!((1.0f64.atan2(1.0) - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
352 assert!((1.0f64.cosh().powi(2) - 1.0f64.sinh().powi(2) - 1.0).abs() < 1e-12);
353 assert!((0.5f64.tanh() - 0.5f64.tanh()).abs() < 1e-12);
354 assert!((1.0f64.asinh() - 1.0f64.asinh()).abs() < 1e-12);
355 assert!((0.001f64.exp_m1() - (0.001f64.exp() - 1.0)).abs() < 1e-15);
356 assert!((0.001f64.ln_1p() - 0.001f64.ln_1p()).abs() < 1e-15);
357 let (s, c) = 0.0f64.sin_cos();
358 assert!((s - 0.0f64.sin()).abs() < 1e-15);
359 assert!((c - 0.0f64.cos()).abs() < 1e-15);
360 assert!((3.0f64.hypot(4.0) - 5.0).abs() < 1e-12);
361 assert_eq!(3.0f64.copysign(-1.0), -3.0);
362 assert_eq!(Real::abs_sub(5.0f64, 3.0), 2.0);
363 assert_eq!(Real::abs_sub(4.0f64, 5.0), 0.0);
364 assert_eq!(4.0f64.recip(), 0.25);
365 assert!((8.0f64.log2() - 3.0).abs() < 1e-12);
366 assert_eq!(2.7f64.trunc(), 2.0);
367 assert!((2.7f64.fract() - 0.7).abs() < 1e-12);
368 assert_eq!((-2.5f64).signum(), -1.0);
369 assert!(1.0f64.is_normal());
370 assert!(!0.0f64.is_normal());
371 assert!(1.0f64.is_sign_positive());
372 assert!((-0.0f64).is_sign_negative());
373 }
374
375 #[test]
376 fn field_reciprocal() {
377 assert_eq!(4.0f64.reciprocal(), 0.25);
378 assert_eq!(Field::div(10.0f32, 4.0), 2.5);
379 }
380}