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}
281
282#[cfg(feature = "std")]
284impl_real!(f32, f64);
285
286#[cfg(all(not(feature = "std"), feature = "libm"))]
288macro_rules! impl_real_libm {
289 ($($t:ty),* $(,)?) => {$(
290 impl Real for $t {
291 fn from_f64(v: f64) -> Self { v as $t }
292 fn to_f64(self) -> f64 { f64::from(self) }
293 fn sqrt(self) -> Self { crate::libm_fallback::sqrt(self as f64) as $t }
294 fn cbrt(self) -> Self { crate::libm_fallback::cbrt(self as f64) as $t }
295 fn powf(self, e: Self) -> Self { crate::libm_fallback::powf(self as f64, e as f64) as $t }
296 fn powi(self, e: i32) -> Self { crate::libm_fallback::powi(self as f64, e) as $t }
297 fn exp(self) -> Self { crate::libm_fallback::exp(self as f64) as $t }
298 fn exp_m1(self) -> Self { crate::libm_fallback::exp_m1(self as f64) as $t }
299 fn ln(self) -> Self { crate::libm_fallback::ln(self as f64) as $t }
300 fn ln_1p(self) -> Self { crate::libm_fallback::ln_1p(self as f64) as $t }
301 fn log(self, base: Self) -> Self { crate::libm_fallback::log(self as f64, base as f64) as $t }
302 fn log10(self) -> Self { crate::libm_fallback::log10(self as f64) as $t }
303 fn log2(self) -> Self { crate::libm_fallback::log2(self as f64) as $t }
304 fn sin(self) -> Self { crate::libm_fallback::sin(self as f64) as $t }
305 fn cos(self) -> Self { crate::libm_fallback::cos(self as f64) as $t }
306 fn tan(self) -> Self { crate::libm_fallback::tan(self as f64) as $t }
307 fn asin(self) -> Self { crate::libm_fallback::asin(self as f64) as $t }
308 fn acos(self) -> Self { crate::libm_fallback::acos(self as f64) as $t }
309 fn atan(self) -> Self { crate::libm_fallback::atan(self as f64) as $t }
310 fn atan2(self, other: Self) -> Self { crate::libm_fallback::atan2(self as f64, other as f64) as $t }
311 fn sinh(self) -> Self { crate::libm_fallback::sinh(self as f64) as $t }
312 fn cosh(self) -> Self { crate::libm_fallback::cosh(self as f64) as $t }
313 fn tanh(self) -> Self { crate::libm_fallback::tanh(self as f64) as $t }
314 fn asinh(self) -> Self { crate::libm_fallback::asinh(self as f64) as $t }
315 fn acosh(self) -> Self { crate::libm_fallback::acosh(self as f64) as $t }
316 fn atanh(self) -> Self { crate::libm_fallback::atanh(self as f64) as $t }
317 fn sin_cos(self) -> (Self, Self) {
318 let (s, c) = crate::libm_fallback::sin_cos(self as f64);
319 (s as $t, c as $t)
320 }
321 fn hypot(self, other: Self) -> Self { crate::libm_fallback::hypot(self as f64, other as f64) as $t }
322 fn copysign(self, other: Self) -> Self {
323 if other.is_sign_negative() {
324 self.abs().neg()
325 } else {
326 self.abs()
327 }
328 }
329 fn abs_sub(self, other: Self) -> Self { (self - other).max(Self::zero()) }
330 fn recip(self) -> Self { 1.0 / self }
331 fn floor(self) -> Self { crate::libm_fallback::floor(self as f64) as $t }
332 fn ceil(self) -> Self { crate::libm_fallback::ceil(self as f64) as $t }
333 fn round(self) -> Self { crate::libm_fallback::round(self as f64) as $t }
334 fn trunc(self) -> Self { crate::libm_fallback::trunc(self as f64) as $t }
335 fn fract(self) -> Self { self - crate::libm_fallback::floor(self as f64) as $t }
336 fn min(self, other: Self) -> Self { if self < other { self } else { other } }
337 fn max(self, other: Self) -> Self { if self > other { self } else { other } }
338 fn is_finite(self) -> bool { self.is_finite() }
339 fn is_nan(self) -> bool { self.is_nan() }
340 fn is_infinite(self) -> bool { self.is_infinite() }
341 fn is_normal(self) -> bool { self.is_normal() }
342 fn is_subnormal(self) -> bool { self.is_finite() && self != 0.0 && self.abs() < Self::MIN_POSITIVE }
343 fn is_sign_negative(self) -> bool { self.is_sign_negative() }
344 fn is_sign_positive(self) -> bool { self.is_sign_positive() }
345 fn signum(self) -> Self { self.signum() }
346 }
347 )*};
348}
349#[cfg(all(not(feature = "std"), feature = "libm"))]
350impl_real_libm!(f32, f64);
351
352impl Normed for f32 {
353 fn norm(self) -> Self {
354 self.abs()
355 }
356}
357impl Normed for f64 {
358 fn norm(self) -> Self {
359 self.abs()
360 }
361}
362impl Normed for i8 {
363 fn norm(self) -> Self {
364 self.abs()
365 }
366}
367impl Normed for i16 {
368 fn norm(self) -> Self {
369 self.abs()
370 }
371}
372impl Normed for i32 {
373 fn norm(self) -> Self {
374 self.abs()
375 }
376}
377impl Normed for i64 {
378 fn norm(self) -> Self {
379 self.abs()
380 }
381}
382impl Normed for isize {
383 fn norm(self) -> Self {
384 self.abs()
385 }
386}
387
388#[cfg(test)]
389#[allow(clippy::suboptimal_flops, clippy::imprecise_flops)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn identity_laws() {
395 for a in 0..100i64 {
396 assert_eq!(a + <i64 as Num>::zero(), a);
397 assert_eq!(a * <i64 as Num>::one(), a);
398 }
399 }
400
401 #[test]
402 fn signed_abs() {
403 assert_eq!((-5i32).abs(), 5);
404 assert_eq!((-2.5f64).abs(), 2.5);
405 assert_eq!((-2.5f64).signum(), -1.0);
406 }
407
408 #[test]
409 fn real_ops() {
410 let x = 9.0f64;
411 assert_eq!(x.sqrt(), 3.0);
412 assert_eq!(x.cbrt(), 2.080083823051904);
413 assert_eq!(x.powi(2), 81.0);
414 assert_eq!(x.powf(0.5), 3.0);
415 assert_eq!(x.ln(), 2.0 * 3.0f64.ln());
416 assert!((1.0f64.sin().powi(2) + 1.0f64.cos().powi(2) - 1.0).abs() < 1e-12);
417 assert!((0.5f64.asin() - 0.5f64.asin()).abs() < 1e-12);
418 assert!((0.5f64.acos() - 0.5f64.acos()).abs() < 1e-12);
419 assert!((1.0f64.atan() - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
420 assert!((1.0f64.atan2(1.0) - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
421 assert!((1.0f64.cosh().powi(2) - 1.0f64.sinh().powi(2) - 1.0).abs() < 1e-12);
422 assert!((0.5f64.tanh() - 0.5f64.tanh()).abs() < 1e-12);
423 assert!((1.0f64.asinh() - 1.0f64.asinh()).abs() < 1e-12);
424 assert!((0.001f64.exp_m1() - (0.001f64.exp() - 1.0)).abs() < 1e-15);
425 assert!((0.001f64.ln_1p() - 0.001f64.ln_1p()).abs() < 1e-15);
426 let (s, c) = 0.0f64.sin_cos();
427 assert!((s - 0.0f64.sin()).abs() < 1e-15);
428 assert!((c - 0.0f64.cos()).abs() < 1e-15);
429 assert!((3.0f64.hypot(4.0) - 5.0).abs() < 1e-12);
430 assert_eq!(3.0f64.copysign(-1.0), -3.0);
431 assert_eq!(Real::abs_sub(5.0f64, 3.0), 2.0);
432 assert_eq!(Real::abs_sub(4.0f64, 5.0), 0.0);
433 assert_eq!(4.0f64.recip(), 0.25);
434 assert!((8.0f64.log2() - 3.0).abs() < 1e-12);
435 assert_eq!(2.7f64.trunc(), 2.0);
436 assert!((2.7f64.fract() - 0.7).abs() < 1e-12);
437 assert_eq!((-2.5f64).signum(), -1.0);
438 assert!(1.0f64.is_normal());
439 assert!(!0.0f64.is_normal());
440 assert!(1.0f64.is_sign_positive());
441 assert!((-0.0f64).is_sign_negative());
442 }
443
444 #[test]
445 fn field_reciprocal() {
446 assert_eq!(4.0f64.reciprocal(), 0.25);
447 assert_eq!(Field::div(10.0f32, 4.0), 2.5);
448 }
449}