1use core::fmt::Debug;
36use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
37
38pub trait Num:
40 Copy + PartialEq + Debug + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
41{
42 fn zero() -> Self;
44 fn one() -> Self;
46 fn from_i64(v: i64) -> Self;
48}
49
50pub trait Signed: Num + Neg<Output = Self> + PartialOrd {
52 fn abs(self) -> Self;
54 fn signum(self) -> Self;
56 fn is_negative(self) -> bool;
58}
59
60pub trait Field: Num + Div<Output = Self> + Rem<Output = Self> {
62 fn div(self, other: Self) -> Self;
64 fn reciprocal(self) -> Self;
66}
67
68pub trait Real: Num + Signed + Div<Output = Self> + Rem<Output = Self> + PartialOrd {
73 fn from_f64(v: f64) -> Self;
75 fn to_f64(self) -> f64;
77 fn epsilon() -> Self;
79
80 fn sqrt(self) -> Self;
82 fn cbrt(self) -> Self;
84 fn powf(self, e: Self) -> Self;
86 fn powi(self, e: i32) -> Self;
88 fn recip(self) -> Self;
90
91 fn floor(self) -> Self;
93 fn ceil(self) -> Self;
95 fn round(self) -> Self;
97 fn trunc(self) -> Self;
99 fn fract(self) -> Self;
101
102 fn copysign(self, other: Self) -> Self;
104 fn abs_sub(self, other: Self) -> Self;
106
107 fn min(self, other: Self) -> Self;
109 fn max(self, other: Self) -> Self;
111}
112
113pub trait Transcendental: Real {
115 fn exp(self) -> Self;
117 fn exp_m1(self) -> Self;
119 fn ln(self) -> Self;
121 fn ln_1p(self) -> Self;
123 fn log(self, base: Self) -> Self;
125 fn log10(self) -> Self;
127 fn log2(self) -> Self;
129}
130
131pub trait Trig: Real {
133 fn sin(self) -> Self;
135 fn cos(self) -> Self;
137 fn tan(self) -> Self;
139 fn asin(self) -> Self;
141 fn acos(self) -> Self;
143 fn atan(self) -> Self;
145 fn atan2(self, other: Self) -> Self;
147 fn sin_cos(self) -> (Self, Self);
149 fn hypot(self, other: Self) -> Self;
151}
152
153pub trait Hyperbolic: Real {
155 fn sinh(self) -> Self;
157 fn cosh(self) -> Self;
159 fn tanh(self) -> Self;
161 fn asinh(self) -> Self;
163 fn acosh(self) -> Self;
165 fn atanh(self) -> Self;
167}
168
169pub trait FloatClass: Real {
171 fn is_finite(self) -> bool;
173 fn is_nan(self) -> bool;
175 fn is_infinite(self) -> bool;
177 fn is_normal(self) -> bool;
179 fn is_subnormal(self) -> bool;
181 fn is_sign_negative(self) -> bool;
183 fn is_sign_positive(self) -> bool;
185}
186
187pub trait RealFull:
191 Real + Transcendental + Trig + Hyperbolic + FloatClass
192{
193}
194impl<T: Real + Transcendental + Trig + Hyperbolic + FloatClass> RealFull for T {}
195
196pub trait Normed: Signed {
200 fn norm(self) -> Self;
202}
203
204macro_rules! impl_num_int {
205 ($($t:ty),* $(,)?) => {$(
206 impl Num for $t {
207 fn zero() -> Self { 0 }
208 fn one() -> Self { 1 }
209 fn from_i64(v: i64) -> Self { v as $t }
210 }
211 )*};
212}
213impl_num_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
214
215macro_rules! impl_num_float {
216 ($($t:ty),* $(,)?) => {$(
217 impl Num for $t {
218 fn zero() -> Self { 0.0 }
219 fn one() -> Self { 1.0 }
220 fn from_i64(v: i64) -> Self { v as $t }
221 }
222 )*};
223}
224impl_num_float!(f32, f64);
225
226macro_rules! impl_signed_int {
227 ($($t:ty),* $(,)?) => {$(
228 impl Signed for $t {
229 fn abs(self) -> Self { self.abs() }
230 fn signum(self) -> Self { self.signum() }
231 fn is_negative(self) -> bool { self < 0 }
232 }
233 )*};
234}
235impl_signed_int!(i8, i16, i32, i64, isize);
236
237macro_rules! impl_signed_float {
238 ($($t:ty),* $(,)?) => {$(
239 impl Signed for $t {
240 fn abs(self) -> Self { self.abs() }
241 fn signum(self) -> Self { self.signum() }
242 fn is_negative(self) -> bool { self.is_sign_negative() }
243 }
244 )*};
245}
246impl_signed_float!(f32, f64);
247
248macro_rules! impl_field_float {
249 ($($t:ty),* $(,)?) => {$(
250 impl Field for $t {
251 fn div(self, other: Self) -> Self { self / other }
252 fn reciprocal(self) -> Self { 1.0 / self }
253 }
254 )*};
255}
256impl_field_float!(f32, f64);
257
258#[cfg(feature = "std")]
259macro_rules! impl_real_core {
260 ($($t:ty),* $(,)?) => {$(
261 impl Real for $t {
262 fn from_f64(v: f64) -> Self { v as $t }
263 fn to_f64(self) -> f64 { f64::from(self) }
264 fn epsilon() -> Self { Self::from_f64($crate::precision::EPS) }
265 fn sqrt(self) -> Self { self.sqrt() }
266 fn cbrt(self) -> Self { self.cbrt() }
267 fn powf(self, e: Self) -> Self { self.powf(e) }
268 fn powi(self, e: i32) -> Self { self.powi(e) }
269 fn recip(self) -> Self { self.recip() }
270 fn floor(self) -> Self { self.floor() }
271 fn ceil(self) -> Self { self.ceil() }
272 fn round(self) -> Self { self.round() }
273 fn trunc(self) -> Self { self.trunc() }
274 fn fract(self) -> Self { self.fract() }
275 fn copysign(self, other: Self) -> Self { self.copysign(other) }
276 fn abs_sub(self, other: Self) -> Self { (self - other).max(Self::zero()) }
277 fn min(self, other: Self) -> Self { self.min(other) }
278 fn max(self, other: Self) -> Self { self.max(other) }
279 }
280 )*};
281}
282
283#[cfg(feature = "std")]
284macro_rules! impl_transcendental {
285 ($($t:ty),* $(,)?) => {$(
286 impl Transcendental for $t {
287 fn exp(self) -> Self { self.exp() }
288 fn exp_m1(self) -> Self { self.exp_m1() }
289 fn ln(self) -> Self { self.ln() }
290 fn ln_1p(self) -> Self { self.ln_1p() }
291 fn log(self, base: Self) -> Self { self.log(base) }
292 fn log10(self) -> Self { self.log10() }
293 fn log2(self) -> Self { self.log2() }
294 }
295 )*};
296}
297
298#[cfg(feature = "std")]
299macro_rules! impl_trig {
300 ($($t:ty),* $(,)?) => {$(
301 impl Trig for $t {
302 fn sin(self) -> Self { self.sin() }
303 fn cos(self) -> Self { self.cos() }
304 fn tan(self) -> Self { self.tan() }
305 fn asin(self) -> Self { self.asin() }
306 fn acos(self) -> Self { self.acos() }
307 fn atan(self) -> Self { self.atan() }
308 fn atan2(self, other: Self) -> Self { self.atan2(other) }
309 fn sin_cos(self) -> (Self, Self) { self.sin_cos() }
310 fn hypot(self, other: Self) -> Self { self.hypot(other) }
311 }
312 )*};
313}
314
315#[cfg(feature = "std")]
316macro_rules! impl_hyperbolic {
317 ($($t:ty),* $(,)?) => {$(
318 impl Hyperbolic for $t {
319 fn sinh(self) -> Self { self.sinh() }
320 fn cosh(self) -> Self { self.cosh() }
321 fn tanh(self) -> Self { self.tanh() }
322 fn asinh(self) -> Self { self.asinh() }
323 fn acosh(self) -> Self { self.acosh() }
324 fn atanh(self) -> Self { self.atanh() }
325 }
326 )*};
327}
328
329#[cfg(feature = "std")]
330macro_rules! impl_float_class {
331 ($($t:ty),* $(,)?) => {$(
332 impl FloatClass for $t {
333 fn is_finite(self) -> bool { self.is_finite() }
334 fn is_nan(self) -> bool { self.is_nan() }
335 fn is_infinite(self) -> bool { self.is_infinite() }
336 fn is_normal(self) -> bool { self.is_normal() }
337 fn is_subnormal(self) -> bool { self.is_subnormal() }
338 fn is_sign_negative(self) -> bool { self.is_sign_negative() }
339 fn is_sign_positive(self) -> bool { self.is_sign_positive() }
340 }
341 )*};
342}
343
344#[cfg(feature = "std")]
346mod real_impls {
347 use super::{Num, Real, Transcendental, Trig, Hyperbolic, FloatClass};
348 impl_real_core!(f32, f64);
349 impl_transcendental!(f32, f64);
350 impl_trig!(f32, f64);
351 impl_hyperbolic!(f32, f64);
352 impl_float_class!(f32, f64);
353}
354
355#[cfg(all(not(feature = "std"), feature = "libm"))]
357mod real_impls {
358 use super::{Num, Real, Transcendental, Trig, Hyperbolic, FloatClass};
359
360 macro_rules! impl_real_core_libm {
361 ($($t:ty),* $(,)?) => {$(
362 impl Real for $t {
363 fn from_f64(v: f64) -> Self { v as $t }
364 fn to_f64(self) -> f64 { f64::from(self) }
365 fn epsilon() -> Self { Self::from_f64($crate::precision::EPS) }
366 fn sqrt(self) -> Self { crate::libm_fallback::sqrt(self as f64) as $t }
367 fn cbrt(self) -> Self { crate::libm_fallback::cbrt(self as f64) as $t }
368 fn powf(self, e: Self) -> Self { crate::libm_fallback::powf(self as f64, e as f64) as $t }
369 fn powi(self, e: i32) -> Self { crate::libm_fallback::powi(self as f64, e) as $t }
370 fn recip(self) -> Self { 1.0 / self }
371 fn floor(self) -> Self { crate::libm_fallback::floor(self as f64) as $t }
372 fn ceil(self) -> Self { crate::libm_fallback::ceil(self as f64) as $t }
373 fn round(self) -> Self { crate::libm_fallback::round(self as f64) as $t }
374 fn trunc(self) -> Self { crate::libm_fallback::trunc(self as f64) as $t }
375 fn fract(self) -> Self { self - crate::libm_fallback::floor(self as f64) as $t }
376 fn copysign(self, other: Self) -> Self {
377 if other.is_sign_negative() { -self.abs() } else { self.abs() }
378 }
379 fn abs_sub(self, other: Self) -> Self { (self - other).max(Self::zero()) }
380 fn min(self, other: Self) -> Self { if self < other { self } else { other } }
381 fn max(self, other: Self) -> Self { if self > other { self } else { other } }
382 }
383 )*};
384 }
385
386 macro_rules! impl_transcendental_libm {
387 ($($t:ty),* $(,)?) => {$(
388 impl Transcendental for $t {
389 fn exp(self) -> Self { crate::libm_fallback::exp(self as f64) as $t }
390 fn exp_m1(self) -> Self { crate::libm_fallback::exp_m1(self as f64) as $t }
391 fn ln(self) -> Self { crate::libm_fallback::ln(self as f64) as $t }
392 fn ln_1p(self) -> Self { crate::libm_fallback::ln_1p(self as f64) as $t }
393 fn log(self, base: Self) -> Self { crate::libm_fallback::log(self as f64, base as f64) as $t }
394 fn log10(self) -> Self { crate::libm_fallback::log10(self as f64) as $t }
395 fn log2(self) -> Self { crate::libm_fallback::log2(self as f64) as $t }
396 }
397 )*};
398 }
399
400 macro_rules! impl_trig_libm {
401 ($($t:ty),* $(,)?) => {$(
402 impl Trig for $t {
403 fn sin(self) -> Self { crate::libm_fallback::sin(self as f64) as $t }
404 fn cos(self) -> Self { crate::libm_fallback::cos(self as f64) as $t }
405 fn tan(self) -> Self { crate::libm_fallback::tan(self as f64) as $t }
406 fn asin(self) -> Self { crate::libm_fallback::asin(self as f64) as $t }
407 fn acos(self) -> Self { crate::libm_fallback::acos(self as f64) as $t }
408 fn atan(self) -> Self { crate::libm_fallback::atan(self as f64) as $t }
409 fn atan2(self, other: Self) -> Self { crate::libm_fallback::atan2(self as f64, other as f64) as $t }
410 fn sin_cos(self) -> (Self, Self) {
411 let (s, c) = crate::libm_fallback::sin_cos(self as f64);
412 (s as $t, c as $t)
413 }
414 fn hypot(self, other: Self) -> Self { crate::libm_fallback::hypot(self as f64, other as f64) as $t }
415 }
416 )*};
417 }
418
419 macro_rules! impl_hyperbolic_libm {
420 ($($t:ty),* $(,)?) => {$(
421 impl Hyperbolic for $t {
422 fn sinh(self) -> Self { crate::libm_fallback::sinh(self as f64) as $t }
423 fn cosh(self) -> Self { crate::libm_fallback::cosh(self as f64) as $t }
424 fn tanh(self) -> Self { crate::libm_fallback::tanh(self as f64) as $t }
425 fn asinh(self) -> Self { crate::libm_fallback::asinh(self as f64) as $t }
426 fn acosh(self) -> Self { crate::libm_fallback::acosh(self as f64) as $t }
427 fn atanh(self) -> Self { crate::libm_fallback::atanh(self as f64) as $t }
428 }
429 )*};
430 }
431
432 macro_rules! impl_float_class_libm {
433 ($($t:ty),* $(,)?) => {$(
434 impl FloatClass for $t {
435 fn is_finite(self) -> bool { self.is_finite() }
436 fn is_nan(self) -> bool { self.is_nan() }
437 fn is_infinite(self) -> bool { self.is_infinite() }
438 fn is_normal(self) -> bool { self.is_normal() }
439 fn is_subnormal(self) -> bool { self.is_finite() && self != 0.0 && self.abs() < Self::MIN_POSITIVE }
440 fn is_sign_negative(self) -> bool { self.is_sign_negative() }
441 fn is_sign_positive(self) -> bool { self.is_sign_positive() }
442 }
443 )*};
444 }
445
446 impl_real_core_libm!(f32, f64);
447 impl_transcendental_libm!(f32, f64);
448 impl_trig_libm!(f32, f64);
449 impl_hyperbolic_libm!(f32, f64);
450 impl_float_class_libm!(f32, f64);
451}
452
453impl Normed for f32 {
454 fn norm(self) -> Self {
455 self.abs()
456 }
457}
458impl Normed for f64 {
459 fn norm(self) -> Self {
460 self.abs()
461 }
462}
463impl Normed for i8 {
464 fn norm(self) -> Self {
465 self.abs()
466 }
467}
468impl Normed for i16 {
469 fn norm(self) -> Self {
470 self.abs()
471 }
472}
473impl Normed for i32 {
474 fn norm(self) -> Self {
475 self.abs()
476 }
477}
478impl Normed for i64 {
479 fn norm(self) -> Self {
480 self.abs()
481 }
482}
483impl Normed for isize {
484 fn norm(self) -> Self {
485 self.abs()
486 }
487}
488
489#[cfg(test)]
490#[allow(clippy::suboptimal_flops, clippy::imprecise_flops)]
491mod tests {
492 use super::{Field, Num, Real};
493
494 #[test]
495 fn identity_laws() {
496 for a in 0..100i64 {
497 assert_eq!(a + <i64 as Num>::zero(), a);
498 assert_eq!(a * <i64 as Num>::one(), a);
499 }
500 }
501
502 #[test]
503 fn signed_abs() {
504 assert_eq!((-5i32).abs(), 5);
505 assert_eq!((-2.5f64).abs(), 2.5);
506 assert_eq!((-2.5f64).signum(), -1.0);
507 }
508
509 #[test]
510 fn real_ops() {
511 let x = 9.0f64;
512 assert_eq!(x.sqrt(), 3.0);
513 assert_eq!(x.cbrt(), 2.080083823051904);
514 assert_eq!(x.powi(2), 81.0);
515 assert_eq!(x.powf(0.5), 3.0);
516 assert_eq!(x.ln(), 2.0 * 3.0f64.ln());
517 assert!((1.0f64.sin().powi(2) + 1.0f64.cos().powi(2) - 1.0).abs() < 1e-12);
518 assert!((0.5f64.asin() - 0.5f64.asin()).abs() < 1e-12);
519 assert!((0.5f64.acos() - 0.5f64.acos()).abs() < 1e-12);
520 assert!((1.0f64.atan() - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
521 assert!((1.0f64.atan2(1.0) - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
522 assert!((1.0f64.cosh().powi(2) - 1.0f64.sinh().powi(2) - 1.0).abs() < 1e-12);
523 assert!((0.5f64.tanh() - 0.5f64.tanh()).abs() < 1e-12);
524 assert!((1.0f64.asinh() - 1.0f64.asinh()).abs() < 1e-12);
525 assert!((0.001f64.exp_m1() - (0.001f64.exp() - 1.0)).abs() < 1e-15);
526 assert!((0.001f64.ln_1p() - 0.001f64.ln_1p()).abs() < 1e-15);
527 let (s, c) = 0.0f64.sin_cos();
528 assert!((s - 0.0f64.sin()).abs() < 1e-15);
529 assert!((c - 0.0f64.cos()).abs() < 1e-15);
530 assert!((3.0f64.hypot(4.0) - 5.0).abs() < 1e-12);
531 assert_eq!(3.0f64.copysign(-1.0), -3.0);
532 assert_eq!(Real::abs_sub(5.0f64, 3.0), 2.0);
533 assert_eq!(Real::abs_sub(4.0f64, 5.0), 0.0);
534 assert_eq!(4.0f64.recip(), 0.25);
535 assert!((8.0f64.log2() - 3.0).abs() < 1e-12);
536 assert_eq!(2.7f64.trunc(), 2.0);
537 assert!((2.7f64.fract() - 0.7).abs() < 1e-12);
538 assert_eq!((-2.5f64).signum(), -1.0);
539 assert!(1.0f64.is_normal());
540 assert!(!0.0f64.is_normal());
541 assert!(1.0f64.is_sign_positive());
542 assert!((-0.0f64).is_sign_negative());
543 }
544
545 #[test]
546 fn field_reciprocal() {
547 assert_eq!(4.0f64.reciprocal(), 0.25);
548 assert_eq!(Field::div(10.0f32, 4.0), 2.5);
549 }
550}