1use crate::ring::Ring;
5
6pub trait Field: Ring {
8 fn reciprocal(self) -> Self;
9
10 fn div(self, other: Self) -> Self
11 where
12 Self: Sized,
13 {
14 self.mul(other.reciprocal())
15 }
16}
17
18impl Field for f32 {
19 fn reciprocal(self) -> Self {
20 1.0 / self
21 }
22}
23
24impl Field for f64 {
25 fn reciprocal(self) -> Self {
26 1.0 / self
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 macro_rules! assert_approx_eq {
34 ($a:expr, $b:expr) => {
35 assert_approx_eq!($a, $b, 1e-10)
36 };
37 ($a:expr, $b:expr, $eps:expr) => {
38 let (a, b) = ($a as f64, $b as f64);
39 assert!(
40 (a - b).abs() < $eps,
41 "assertion failed: |{} - {}| = {} >= {}",
42 a,
43 b,
44 (a - b).abs(),
45 $eps
46 );
47 };
48 }
49
50 #[test]
51 fn f64_reciprocal() {
52 assert_approx_eq!(2.0f64.reciprocal(), 0.5);
53 assert_approx_eq!(4.0f64.reciprocal(), 0.25);
54 }
55
56 #[test]
57 fn f64_div() {
58 assert_approx_eq!(10.0f64.div(4.0), 2.5);
59 }
60
61 #[test]
62 fn f32_reciprocal() {
63 assert!((2.0f32.reciprocal() - 0.5).abs() < 1e-6);
64 }
65}
66
67#[cfg(test)]
68mod law_tests {
69 use super::*;
70 use crate::semiring::Semiring;
71 use proptest::prelude::*;
72
73 proptest! {
74 #[test]
75 fn f64_multiplicative_inverse(a in proptest::num::f64::NORMAL.prop_filter("non-zero", |x| x.abs() > 1e-10)) {
76 let result = a.mul(a.reciprocal());
77 prop_assert!((result - 1.0).abs() < 1e-6, "a={}, a*a^-1={}", a, result);
78 }
79
80 #[test]
81 fn f64_div_is_mul_reciprocal(
82 a in proptest::num::f64::NORMAL.prop_filter("bounded", |x| x.abs() < 1e6),
83 b in proptest::num::f64::NORMAL.prop_filter("non-zero bounded", |x| x.abs() > 1e-10 && x.abs() < 1e6)
84 ) {
85 let left = a.div(b);
86 let right = a.mul(b.reciprocal());
87 prop_assert!((left - right).abs() < 1e-6, "a/b={}, a*b^-1={}", left, right);
88 }
89 }
90}