1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
7use core::ops::{Add, Div, Mul, Neg, Sub};
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub struct Complex<T> {
12 pub re: T,
14 pub im: T,
16}
17
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20pub struct Imaginary<T>(pub T);
21
22impl<T> Complex<T> {
23 #[must_use]
25 pub const fn new(re: T, im: T) -> Self {
26 Self { re, im }
27 }
28
29 #[must_use]
31 pub const fn real(&self) -> &T {
32 &self.re
33 }
34
35 #[must_use]
37 pub const fn imaginary(&self) -> &T {
38 &self.im
39 }
40}
41
42impl<T> Imaginary<T> {
43 #[must_use]
45 pub const fn new(value: T) -> Self {
46 Self(value)
47 }
48
49 #[must_use]
51 pub const fn value(&self) -> &T {
52 &self.0
53 }
54}
55
56impl<T> Complex<T>
57where
58 T: Default,
59{
60 #[must_use]
62 pub fn from_real(re: T) -> Self {
63 Self::new(re, T::default())
64 }
65
66 #[must_use]
68 pub fn from_imaginary(im: T) -> Self {
69 Self::new(T::default(), im)
70 }
71}
72
73impl<T> Complex<T>
74where
75 T: Default + From<u8>,
76{
77 #[must_use]
79 pub fn zero() -> Self {
80 Self::new(T::default(), T::default())
81 }
82
83 #[must_use]
85 pub fn one() -> Self {
86 Self::from_real(T::from(1_u8))
87 }
88
89 #[must_use]
91 pub fn i() -> Self {
92 Self::from_imaginary(T::from(1_u8))
93 }
94}
95
96impl<T> Complex<T>
97where
98 T: Copy + Neg<Output = T>,
99{
100 #[must_use]
102 pub fn conjugate(&self) -> Self {
103 Self::new(self.re, -self.im)
104 }
105}
106
107impl<T> Complex<T>
108where
109 T: Copy + Add<Output = T> + Mul<Output = T>,
110{
111 #[must_use]
113 pub fn magnitude_squared(&self) -> T {
114 (self.re * self.re) + (self.im * self.im)
115 }
116}
117
118macro_rules! impl_float_methods {
119 ($($ty:ty),* $(,)?) => {
120 $(
121 impl Complex<$ty> {
122 #[must_use]
124 pub fn magnitude(&self) -> $ty {
125 self.magnitude_squared().sqrt()
126 }
127
128 #[must_use]
130 pub fn argument(&self) -> $ty {
131 self.im.atan2(self.re)
132 }
133
134 #[must_use]
136 pub fn from_polar(magnitude: $ty, argument: $ty) -> Self {
137 Self::new(magnitude * argument.cos(), magnitude * argument.sin())
138 }
139
140 #[must_use]
142 pub fn to_polar(&self) -> ($ty, $ty) {
143 (self.magnitude(), self.argument())
144 }
145 }
146 )*
147 };
148}
149
150impl_float_methods!(f32, f64);
151
152impl<T> From<T> for Complex<T>
153where
154 T: Default,
155{
156 fn from(value: T) -> Self {
157 Self::from_real(value)
158 }
159}
160
161impl<T> From<Imaginary<T>> for Complex<T>
162where
163 T: Default,
164{
165 fn from(value: Imaginary<T>) -> Self {
166 Self::from_imaginary(value.0)
167 }
168}
169
170impl<T> From<T> for Imaginary<T> {
171 fn from(value: T) -> Self {
172 Self(value)
173 }
174}
175
176impl<T> Add for Complex<T>
177where
178 T: Add<Output = T>,
179{
180 type Output = Self;
181
182 fn add(self, rhs: Self) -> Self::Output {
183 Self::new(self.re + rhs.re, self.im + rhs.im)
184 }
185}
186
187impl<T> Sub for Complex<T>
188where
189 T: Sub<Output = T>,
190{
191 type Output = Self;
192
193 fn sub(self, rhs: Self) -> Self::Output {
194 Self::new(self.re - rhs.re, self.im - rhs.im)
195 }
196}
197
198#[allow(clippy::suspicious_arithmetic_impl)]
199impl<T> Mul for Complex<T>
200where
201 T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
202{
203 type Output = Self;
204
205 fn mul(self, rhs: Self) -> Self::Output {
206 let re = (self.re * rhs.re) - (self.im * rhs.im);
207 let im = (self.re * rhs.im) + (self.im * rhs.re);
208
209 Self::new(re, im)
210 }
211}
212
213#[allow(clippy::suspicious_arithmetic_impl)]
214impl<T> Div for Complex<T>
215where
216 T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
217{
218 type Output = Self;
219
220 fn div(self, rhs: Self) -> Self::Output {
221 let denominator = (rhs.re * rhs.re) + (rhs.im * rhs.im);
222 let re = ((self.re * rhs.re) + (self.im * rhs.im)) / denominator;
223 let im = ((self.im * rhs.re) - (self.re * rhs.im)) / denominator;
224
225 Self::new(re, im)
226 }
227}
228
229impl<T> Neg for Complex<T>
230where
231 T: Neg<Output = T>,
232{
233 type Output = Self;
234
235 fn neg(self) -> Self::Output {
236 Self::new(-self.re, -self.im)
237 }
238}
239
240impl<T> fmt::Display for Complex<T>
241where
242 T: Copy + Default + fmt::Display + Neg<Output = T> + PartialEq + PartialOrd,
243{
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 let zero = T::default();
246
247 if self.im == zero {
248 return write!(f, "{}", self.re);
249 }
250
251 if self.re == zero {
252 if self.im < zero {
253 return write!(f, "-{}i", -self.im);
254 }
255
256 return write!(f, "{}i", self.im);
257 }
258
259 if self.im < zero {
260 return write!(f, "{} - {}i", self.re, -self.im);
261 }
262
263 write!(f, "{} + {}i", self.re, self.im)
264 }
265}
266
267impl<T> fmt::Display for Imaginary<T>
268where
269 T: Copy + Default + fmt::Display + Neg<Output = T> + PartialEq + PartialOrd,
270{
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 let zero = T::default();
273
274 if self.0 < zero {
275 return write!(f, "-{}i", -self.0);
276 }
277
278 if self.0 == zero {
279 return write!(f, "0i");
280 }
281
282 write!(f, "{}i", self.0)
283 }
284}
285
286pub mod prelude;
287
288#[cfg(test)]
289mod tests {
290 use super::{Complex, Imaginary};
291 use core::f64::consts::{FRAC_PI_2, FRAC_PI_3};
292
293 fn assert_close(lhs: f64, rhs: f64) {
294 let difference = (lhs - rhs).abs();
295
296 assert!(
297 difference <= 1.0e-10,
298 "left={lhs}, right={rhs}, diff={difference}"
299 );
300 }
301
302 #[test]
303 fn constructs_complex_values_and_accessors() {
304 let value = Complex::new(3_i32, 4_i32);
305
306 assert_eq!(value.re, 3);
307 assert_eq!(value.im, 4);
308 assert_eq!(value.real(), &3);
309 assert_eq!(value.imaginary(), &4);
310 }
311
312 #[test]
313 fn supports_imaginary_only_values() {
314 let imaginary = Imaginary::new(4_i32);
315 let complex = Complex::from(imaginary);
316
317 assert_eq!(imaginary.value(), &4);
318 assert_eq!(imaginary.to_string(), "4i");
319 assert_eq!(complex, Complex::new(0, 4));
320 assert_eq!(Complex::<i32>::from_imaginary(7), Complex::new(0, 7));
321 }
322
323 #[test]
324 fn provides_zero_one_and_i() {
325 assert_eq!(Complex::<i32>::zero(), Complex::new(0, 0));
326 assert_eq!(Complex::<i32>::one(), Complex::new(1, 0));
327 assert_eq!(Complex::<i32>::i(), Complex::new(0, 1));
328 assert_eq!(Complex::<i32>::from_real(9), Complex::new(9, 0));
329 }
330
331 #[test]
332 fn adds_and_subtracts_complex_values() {
333 let lhs = Complex::new(3_i32, 4_i32);
334 let rhs = Complex::new(1_i32, -2_i32);
335
336 assert_eq!(lhs + rhs, Complex::new(4, 2));
337 assert_eq!(lhs - rhs, Complex::new(2, 6));
338 }
339
340 #[test]
341 fn multiplies_complex_values() {
342 let lhs = Complex::new(3_i32, 4_i32);
343 let rhs = Complex::new(1_i32, -2_i32);
344
345 assert_eq!(lhs * rhs, Complex::new(11, -2));
346 }
347
348 #[test]
349 fn divides_complex_values() {
350 let lhs = Complex::new(3.0_f64, 4.0_f64);
351 let rhs = Complex::new(1.0_f64, -2.0_f64);
352 let quotient = lhs / rhs;
353
354 assert_close(quotient.re, -1.0);
355 assert_close(quotient.im, 2.0);
356 }
357
358 #[test]
359 fn negates_and_conjugates() {
360 let value = Complex::new(3_i32, -4_i32);
361
362 assert_eq!(-value, Complex::new(-3, 4));
363 assert_eq!(value.conjugate(), Complex::new(3, 4));
364 }
365
366 #[test]
367 fn computes_magnitude_squared_for_integer_values() {
368 let value = Complex::new(3_i32, 4_i32);
369
370 assert_eq!(value.magnitude_squared(), 25);
371 }
372
373 #[test]
374 fn computes_magnitude_and_argument_for_floats() {
375 let value = Complex::new(3.0_f64, 4.0_f64);
376
377 assert_close(value.magnitude(), 5.0);
378 assert_close(Complex::new(0.0_f64, 4.0_f64).argument(), FRAC_PI_2);
379 }
380
381 #[test]
382 fn converts_to_and_from_polar_form() {
383 let value = Complex::<f64>::from_polar(5.0_f64, FRAC_PI_3);
384 let (magnitude, argument) = value.to_polar();
385
386 assert_close(magnitude, 5.0);
387 assert_close(argument, FRAC_PI_3);
388 }
389
390 #[test]
391 fn formats_complex_and_imaginary_values() {
392 assert_eq!(Complex::new(3_i32, 4_i32).to_string(), "3 + 4i");
393 assert_eq!(Complex::new(3_i32, -4_i32).to_string(), "3 - 4i");
394 assert_eq!(Complex::new(0_i32, 4_i32).to_string(), "4i");
395 assert_eq!(Complex::new(3_i32, 0_i32).to_string(), "3");
396 assert_eq!(Imaginary::new(-4_i32).to_string(), "-4i");
397 }
398
399 #[test]
400 fn integer_division_works_when_components_divide_evenly() {
401 let lhs = Complex::new(4_i32, 2_i32);
402 let rhs = Complex::new(2_i32, 0_i32);
403
404 assert_eq!(lhs / rhs, Complex::new(2, 1));
405 }
406
407 #[test]
408 fn floating_point_values_round_trip_through_helpers() {
409 let from_real = Complex::<f64>::from(3.0);
410 let from_imaginary = Complex::<f64>::from(Imaginary::new(2.5));
411
412 assert_close(from_real.re, 3.0);
413 assert_close(from_real.im, 0.0);
414 assert_close(from_imaginary.re, 0.0);
415 assert_close(from_imaginary.im, 2.5);
416 }
417}