Skip to main content

fp_library/classes/
division_ring.rs

1//! Types that support multiplicative inverses.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::classes::DivisionRing;
7//!
8//! assert_eq!(f64::reciprocate(2.0), 0.5);
9//! ```
10
11#[fp_macros::document_module]
12mod inner {
13	use {
14		crate::classes::*,
15		fp_macros::*,
16	};
17
18	/// A type class for [`Ring`] types that support multiplicative inverses.
19	///
20	/// ### Laws
21	///
22	/// * Non-zero ring: `one != zero`
23	/// * Multiplicative inverse: For all non-zero `a`,
24	///   `multiply(reciprocate(a), a) = multiply(a, reciprocate(a)) = one`
25	///
26	/// The behaviour of `reciprocate(zero)` is undefined.
27	#[document_examples]
28	///
29	/// ```
30	/// use fp_library::classes::{
31	/// 	DivisionRing,
32	/// 	Semiring,
33	/// };
34	///
35	/// let a = 4.0f64;
36	/// assert_eq!(f64::multiply(f64::reciprocate(a), a), f64::one());
37	/// ```
38	pub trait DivisionRing: Ring {
39		/// Computes the multiplicative inverse.
40		#[document_signature]
41		///
42		#[document_parameters("The value to invert.")]
43		///
44		#[document_returns("The multiplicative inverse.")]
45		#[document_examples]
46		///
47		/// ```
48		/// use fp_library::classes::DivisionRing;
49		///
50		/// assert_eq!(f64::reciprocate(4.0), 0.25);
51		/// ```
52		fn reciprocate(a: Self) -> Self;
53	}
54
55	/// Computes the multiplicative inverse.
56	///
57	/// Free function version that dispatches to [`DivisionRing::reciprocate`].
58	#[document_signature]
59	///
60	#[document_type_parameters("The division ring type.")]
61	///
62	#[document_parameters("The value to invert.")]
63	///
64	#[document_returns("The multiplicative inverse.")]
65	#[document_examples]
66	///
67	/// ```
68	/// use fp_library::classes::division_ring::reciprocate;
69	///
70	/// assert_eq!(reciprocate(2.0f64), 0.5);
71	/// ```
72	pub fn reciprocate<D: DivisionRing>(a: D) -> D {
73		D::reciprocate(a)
74	}
75
76	/// Divides from the left: `multiply(reciprocate(b), a)`.
77	#[document_signature]
78	///
79	#[document_type_parameters("The division ring type.")]
80	///
81	#[document_parameters("The dividend.", "The divisor.")]
82	///
83	#[document_returns("The result of left division.")]
84	#[document_examples]
85	///
86	/// ```
87	/// use fp_library::classes::division_ring::divide_left;
88	///
89	/// assert_eq!(divide_left(6.0f64, 2.0), 3.0);
90	/// ```
91	pub fn divide_left<D: DivisionRing>(
92		a: D,
93		b: D,
94	) -> D {
95		D::multiply(D::reciprocate(b), a)
96	}
97
98	/// Divides from the right: `multiply(a, reciprocate(b))`.
99	#[document_signature]
100	///
101	#[document_type_parameters("The division ring type.")]
102	///
103	#[document_parameters("The dividend.", "The divisor.")]
104	///
105	#[document_returns("The result of right division.")]
106	#[document_examples]
107	///
108	/// ```
109	/// use fp_library::classes::division_ring::divide_right;
110	///
111	/// assert_eq!(divide_right(6.0f64, 2.0), 3.0);
112	/// ```
113	pub fn divide_right<D: DivisionRing>(
114		a: D,
115		b: D,
116	) -> D {
117		D::multiply(a, D::reciprocate(b))
118	}
119
120	impl DivisionRing for f32 {
121		/// Computes the multiplicative inverse using `1.0 / a`.
122		#[document_signature]
123		///
124		#[document_parameters("The value to invert.")]
125		///
126		#[document_returns("The multiplicative inverse.")]
127		#[document_examples]
128		///
129		/// ```
130		/// use fp_library::classes::DivisionRing;
131		///
132		/// assert_eq!(f32::reciprocate(4.0), 0.25);
133		/// ```
134		fn reciprocate(a: Self) -> Self {
135			1.0 / a
136		}
137	}
138
139	impl DivisionRing for f64 {
140		/// Computes the multiplicative inverse using `1.0 / a`.
141		#[document_signature]
142		///
143		#[document_parameters("The value to invert.")]
144		///
145		#[document_returns("The multiplicative inverse.")]
146		#[document_examples]
147		///
148		/// ```
149		/// use fp_library::classes::DivisionRing;
150		///
151		/// assert_eq!(f64::reciprocate(4.0), 0.25);
152		/// ```
153		fn reciprocate(a: Self) -> Self {
154			1.0 / a
155		}
156	}
157}
158
159pub use inner::*;