abels_complex/
rectangular.rs

1use crate::polar::*;
2use core::f32::consts::{LN_2, LN_10};
3use core::fmt;
4use core::ops::*;
5use core::write;
6#[cfg(feature = "libm")]
7use num_traits::real::Real;
8
9/// Creates a complex number in rectangular form.
10#[inline(always)]
11#[must_use]
12pub const fn complex(re: f32, im: f32) -> Complex {
13    Complex::new(re, im)
14}
15
16/// A complex number in rectangular form.
17#[derive(Clone, Copy, PartialEq, Debug)]
18#[repr(C)]
19pub struct Complex {
20    pub re: f32,
21    pub im: f32,
22}
23
24impl Complex {
25    pub const ZERO: Self = complex(0.0, 0.0);
26    pub const ONE: Self = complex(1.0, 0.0);
27    pub const NEG_ONE: Self = complex(-1.0, 0.0);
28    pub const I: Self = complex(0.0, 1.0);
29    pub const NEG_I: Self = complex(0.0, -1.0);
30
31    /// Creates a complex number.
32    pub const fn new(re: f32, im: f32) -> Self {
33        Self { re, im }
34    }
35
36    /// Computes the conjugate.
37    pub const fn conjugate(self) -> Self {
38        complex(self.re, -self.im)
39    }
40
41    /// Computes the absolute value.
42    pub fn abs(self) -> f32 {
43        self.abs_sq().sqrt()
44    }
45
46    /// Computes the squared absolute value.
47    ///
48    /// This is faster than `abs()` as it avoids a square root operation.
49    pub fn abs_sq(self) -> f32 {
50        self.re * self.re + self.im * self.im
51    }
52
53    /// Computes the argument in the range `(-π, +π]`.
54    pub fn arg(self) -> f32 {
55        self.im.atan2(self.re)
56    }
57
58    /// Computes the reciprocal.
59    pub fn recip(self) -> Self {
60        self.conjugate() / self.abs_sq()
61    }
62
63    /// Computes the principle square root.
64    pub fn sqrt(self) -> Self {
65        let abs = self.abs();
66        complex(
67            (0.5 * (abs + self.re)).sqrt(),
68            (0.5 * (abs - self.re)).sqrt().copysign(self.im),
69        )
70    }
71
72    /// Convert to polar form.
73    pub fn to_polar(self) -> ComplexPolar {
74        complex_polar(self.abs(), self.arg())
75    }
76
77    /// Computes `e^self` where `e` is the base of the natural logarithm.
78    pub fn exp(self) -> ComplexPolar {
79        complex_polar(self.re.exp(), self.im)
80    }
81
82    /// Computes the principle natural logarithm.
83    pub fn ln(self) -> Self {
84        self.to_polar().ln()
85    }
86
87    /// Computes the principle logarithm in base 2.
88    pub fn log2(self) -> Self {
89        self.ln() / LN_2
90    }
91
92    /// Computes the principle logarithm in base 10.
93    pub fn log10(self) -> Self {
94        self.ln() / LN_10
95    }
96
97    /// Raises `self` to an integer power.
98    pub fn powi(self, n: i32) -> ComplexPolar {
99        self.to_polar().powi(n)
100    }
101
102    /// Raises `self` to a floating point power.
103    pub fn powf(self, x: f32) -> ComplexPolar {
104        self.to_polar().powf(x)
105    }
106
107    /// Computes the euclidian distance between two points.
108    pub fn distance(self, other: Self) -> f32 {
109        (self - other).abs()
110    }
111
112    /// Computes the squared euclidian distance between two points.
113    pub fn distance_squared(self, other: Self) -> f32 {
114        (self - other).abs_sq()
115    }
116
117    /// Casts to a glam::Vec2.
118    #[cfg(feature = "glam")]
119    pub fn as_vec2(self) -> glam::Vec2 {
120        glam::vec2(self.re, self.im)
121    }
122}
123
124impl Add for Complex {
125    type Output = Self;
126    fn add(mut self, other: Self) -> Self::Output {
127        self += other;
128        self
129    }
130}
131
132impl Add<f32> for Complex {
133    type Output = Self;
134    fn add(mut self, re: f32) -> Self::Output {
135        self += re;
136        self
137    }
138}
139
140impl Add<Complex> for f32 {
141    type Output = Complex;
142    fn add(self, mut z: Complex) -> Self::Output {
143        z += self;
144        z
145    }
146}
147
148impl AddAssign for Complex {
149    fn add_assign(&mut self, other: Self) {
150        self.re += other.re;
151        self.im += other.im;
152    }
153}
154
155impl AddAssign<f32> for Complex {
156    fn add_assign(&mut self, re: f32) {
157        self.re += re;
158    }
159}
160
161impl Sub for Complex {
162    type Output = Self;
163    fn sub(mut self, other: Self) -> Self::Output {
164        self -= other;
165        self
166    }
167}
168
169impl Sub<f32> for Complex {
170    type Output = Self;
171    fn sub(mut self, re: f32) -> Self::Output {
172        self -= re;
173        self
174    }
175}
176
177impl Sub<Complex> for f32 {
178    type Output = Complex;
179    fn sub(self, z: Complex) -> Self::Output {
180        complex(self - z.re, -z.im)
181    }
182}
183
184impl SubAssign for Complex {
185    fn sub_assign(&mut self, other: Self) {
186        self.re -= other.re;
187        self.im -= other.im;
188    }
189}
190
191impl SubAssign<f32> for Complex {
192    fn sub_assign(&mut self, re: f32) {
193        self.re -= re;
194    }
195}
196
197impl Mul for Complex {
198    type Output = Self;
199    fn mul(mut self, other: Self) -> Self::Output {
200        self *= other;
201        self
202    }
203}
204
205impl Mul<f32> for Complex {
206    type Output = Self;
207    fn mul(mut self, re: f32) -> Self::Output {
208        self *= re;
209        self
210    }
211}
212
213impl Mul<Complex> for f32 {
214    type Output = Complex;
215    fn mul(self, mut other: Complex) -> Self::Output {
216        other *= self;
217        other
218    }
219}
220
221impl MulAssign for Complex {
222    fn mul_assign(&mut self, other: Self) {
223        let re = self.re * other.re - self.im * other.im;
224        self.im = self.re * other.im + self.im * other.re;
225        self.re = re;
226    }
227}
228
229impl MulAssign<f32> for Complex {
230    fn mul_assign(&mut self, re: f32) {
231        self.re *= re;
232        self.im *= re;
233    }
234}
235
236impl Div for Complex {
237    type Output = Self;
238    fn div(self, other: Self) -> Self::Output {
239        self * other.recip()
240    }
241}
242
243impl Div<f32> for Complex {
244    type Output = Self;
245    fn div(mut self, re: f32) -> Self::Output {
246        self /= re;
247        self
248    }
249}
250
251impl Div<Complex> for f32 {
252    type Output = Complex;
253    fn div(self, other: Complex) -> Self::Output {
254        self * other.recip()
255    }
256}
257
258impl DivAssign for Complex {
259    fn div_assign(&mut self, other: Self) {
260        *self = *self / other;
261    }
262}
263
264impl DivAssign<f32> for Complex {
265    fn div_assign(&mut self, re: f32) {
266        self.re /= re;
267        self.im /= re;
268    }
269}
270
271impl Neg for Complex {
272    type Output = Self;
273    fn neg(self) -> Self::Output {
274        complex(-self.re, -self.im)
275    }
276}
277
278impl fmt::Display for Complex {
279    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280        fn fmt_x(f: &mut fmt::Formatter, x: f32, sign_plus: bool) -> fmt::Result {
281            match (f.precision(), sign_plus) {
282                (None, false) => write!(f, "{}", x),
283                (None, true) => write!(f, "{:+}", x),
284                (Some(p), false) => write!(f, "{:.*}", p, x),
285                (Some(p), true) => write!(f, "{:+.*}", p, x),
286            }
287        }
288        match (self.re, self.im, f.sign_plus()) {
289            (re, 0.0, sp) => fmt_x(f, re, sp),
290            (0.0, 1.0, false) => write!(f, "i"),
291            (0.0, 1.0, true) => write!(f, "+i"),
292            (0.0, -1.0, _) => write!(f, "-i"),
293            (0.0, im, sp) => {
294                fmt_x(f, im, sp)?;
295                write!(f, "i")
296            }
297            (re, 1.0, sp) => {
298                fmt_x(f, re, sp)?;
299                write!(f, "+i")
300            }
301            (re, -1.0, sp) => {
302                fmt_x(f, re, sp)?;
303                write!(f, "-i")
304            }
305            (re, im, sp) => {
306                fmt_x(f, re, sp)?;
307                fmt_x(f, im, true)?;
308                write!(f, "i")
309            }
310        }
311    }
312}
313
314#[cfg(feature = "rand")]
315impl rand::distr::Distribution<Complex> for rand::distr::StandardUniform {
316    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Complex {
317        rng.sample::<ComplexPolar, _>(self).to_rectangular()
318    }
319}
320
321#[cfg(feature = "approx")]
322use approx::{AbsDiffEq, RelativeEq, UlpsEq};
323
324#[cfg(feature = "approx")]
325impl AbsDiffEq for Complex {
326    type Epsilon = <f32 as AbsDiffEq>::Epsilon;
327    fn default_epsilon() -> Self::Epsilon {
328        f32::default_epsilon()
329    }
330    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
331        f32::abs_diff_eq(&self.re, &other.re, epsilon)
332            && f32::abs_diff_eq(&self.im, &other.im, epsilon)
333    }
334}
335
336#[cfg(feature = "approx")]
337impl RelativeEq for Complex {
338    fn default_max_relative() -> Self::Epsilon {
339        f32::default_max_relative()
340    }
341    fn relative_eq(
342        &self,
343        other: &Self,
344        epsilon: Self::Epsilon,
345        max_relative: Self::Epsilon,
346    ) -> bool {
347        f32::relative_eq(&self.re, &other.re, epsilon, max_relative)
348            && f32::relative_eq(&self.im, &other.im, epsilon, max_relative)
349    }
350}
351
352#[cfg(feature = "approx")]
353impl UlpsEq for Complex {
354    fn default_max_ulps() -> u32 {
355        f32::default_max_ulps()
356    }
357    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
358        f32::ulps_eq(&self.re, &other.re, epsilon, max_ulps)
359            && f32::ulps_eq(&self.im, &other.im, epsilon, max_ulps)
360    }
361}
362
363impl From<f32> for Complex {
364    fn from(value: f32) -> Self {
365        complex(value, 0.0)
366    }
367}
368
369#[cfg(feature = "glam")]
370impl From<glam::Vec2> for Complex {
371    fn from(v: glam::Vec2) -> Self {
372        complex(v.x, v.y)
373    }
374}
375
376#[cfg(feature = "glam")]
377impl From<Complex> for glam::Vec2 {
378    fn from(z: Complex) -> Self {
379        z.as_vec2()
380    }
381}
382
383#[cfg(test)]
384mod tests {
385    use super::*;
386    use approx::*;
387    use core::f32::consts::{E, FRAC_PI_2, PI, SQRT_2};
388    use core::iter::Iterator;
389    use rand::{
390        Rng, SeedableRng,
391        distr::{Distribution, StandardUniform},
392        rngs::StdRng,
393    };
394
395    const NUM_SAMPLES: usize = 100;
396
397    fn random_samples<T>() -> impl Iterator<Item = T>
398    where
399        StandardUniform: Distribution<T>,
400    {
401        StdRng::seed_from_u64(21)
402            .sample_iter(StandardUniform)
403            .take(NUM_SAMPLES)
404    }
405
406    #[test]
407    fn addition() {
408        for z0 in random_samples::<Complex>() {
409            for z1 in random_samples::<Complex>() {
410                let z = z0 + z1;
411                assert_eq!(z.re, z0.re + z1.re);
412                assert_eq!(z.im, z0.im + z1.im);
413
414                let z = z0 + z1.re;
415                assert_eq!(z.re, z0.re + z1.re);
416                assert_eq!(z.im, z0.im);
417
418                let z = z0.re + z1;
419                assert_eq!(z.re, z0.re + z1.re);
420                assert_eq!(z.im, z1.im);
421
422                let mut z = z0;
423                z += z1;
424                assert_eq!(z, z0 + z1);
425
426                let mut z = z0;
427                z += z1.re;
428                assert_eq!(z, z0 + z1.re);
429            }
430            assert_eq!(z0 + Complex::ZERO, z0);
431        }
432    }
433
434    #[test]
435    fn subtraction() {
436        for z0 in random_samples::<Complex>() {
437            for z1 in random_samples::<Complex>() {
438                let z = z0 - z1;
439                assert_eq!(z.re, z0.re - z1.re);
440                assert_eq!(z.im, z0.im - z1.im);
441
442                let z = z0 - z1.re;
443                assert_eq!(z.re, z0.re - z1.re);
444                assert_eq!(z.im, z0.im);
445
446                let z = z0.re - z1;
447                assert_eq!(z.re, z0.re - z1.re);
448                assert_eq!(z.im, -z1.im);
449
450                let mut z = z0;
451                z -= z1;
452                assert_eq!(z, z0 - z1);
453
454                let mut z = z0;
455                z -= z1.re;
456                assert_eq!(z, z0 - z1.re);
457            }
458            assert_eq!(z0 - z0, Complex::ZERO);
459            assert_eq!(z0 - Complex::ZERO, z0);
460        }
461    }
462
463    #[test]
464    fn multiplication() {
465        for z0 in random_samples::<Complex>() {
466            for z1 in random_samples::<Complex>() {
467                let z = z0 * z1;
468                assert_ulps_eq!(z.abs(), z0.abs() * z1.abs());
469                assert_ulps_eq!(
470                    z.arg().sin(),
471                    (z0.arg() + z1.arg()).sin(),
472                    epsilon = 4.0 * f32::EPSILON
473                );
474
475                let z = z0 * z1.re;
476                assert_eq!(z.re, z0.re * z1.re);
477                assert_eq!(z.im, z0.im * z1.re);
478
479                let z = z0.re * z1;
480                assert_eq!(z.re, z0.re * z1.re);
481                assert_eq!(z.im, z0.re * z1.im);
482
483                let mut z = z0;
484                z *= z1;
485                assert_eq!(z, z0 * z1);
486
487                let mut z = z0;
488                z *= z1.re;
489                assert_eq!(z, z0 * z1.re);
490            }
491            assert_eq!(z0 * Complex::ONE, z0);
492            assert_eq!(z0 * Complex::ZERO, Complex::ZERO);
493            assert_eq!(z0 * 0.0, Complex::ZERO);
494        }
495    }
496
497    #[test]
498    fn division() {
499        for z0 in random_samples::<Complex>() {
500            for z1 in random_samples::<Complex>() {
501                let z = z0 / z1;
502                assert_relative_eq!(
503                    z.abs(),
504                    z0.abs() / z1.abs(),
505                    max_relative = 3.0 * f32::EPSILON
506                );
507                assert_ulps_eq!(
508                    z.arg().sin(),
509                    (z0.arg() - z1.arg()).sin(),
510                    epsilon = 4.0 * f32::EPSILON
511                );
512
513                let z = z0 / z1.re;
514                assert_eq!(z.re, z0.re / z1.re);
515                assert_eq!(z.im, z0.im / z1.re);
516
517                let z = z0.re / z1;
518                assert_ulps_eq!(z.abs(), z0.re.abs() / z1.abs());
519                assert_ulps_eq!(
520                    z.arg().sin(),
521                    (-z0.re.signum() * z1.arg()).sin(),
522                    epsilon = 2.0 * f32::EPSILON
523                );
524
525                let mut z = z0;
526                z /= z1;
527                assert_eq!(z, z0 / z1);
528
529                let mut z = z0;
530                z /= z1.re;
531                assert_eq!(z, z0 / z1.re);
532            }
533            assert_ulps_eq!(z0 / z0, Complex::ONE);
534            assert_eq!(Complex::ZERO / z0, Complex::ZERO);
535        }
536    }
537
538    #[test]
539    fn negation() {
540        for z in random_samples::<Complex>() {
541            assert_eq!(-z, complex(-z.re, -z.im));
542        }
543        assert_eq!(-Complex::ONE, Complex::NEG_ONE);
544        assert_eq!(-Complex::I, Complex::NEG_I);
545        assert_eq!(-Complex::NEG_ONE, Complex::ONE);
546        assert_eq!(-Complex::NEG_I, Complex::I);
547    }
548
549    #[test]
550    fn reciprocal() {
551        for z in random_samples::<Complex>() {
552            assert_eq!(z.recip(), 1.0 / z);
553            assert_ulps_eq!(z * z.recip(), Complex::ONE);
554        }
555        assert_eq!(Complex::ONE.recip(), Complex::ONE);
556        assert_eq!(Complex::I.recip(), Complex::NEG_I);
557        assert_eq!(Complex::NEG_ONE.recip(), Complex::NEG_ONE);
558        assert_eq!(Complex::NEG_I.recip(), Complex::I);
559    }
560
561    #[test]
562    fn sqrt() {
563        for z in random_samples::<Complex>() {
564            assert_ulps_eq!(z.sqrt().abs(), z.abs().sqrt());
565            assert_ulps_eq!(
566                z.sqrt().arg(),
567                z.arg() / 2.0,
568                epsilon = 1400.0 * f32::EPSILON
569            );
570        }
571        assert_eq!(Complex::ONE.sqrt(), Complex::ONE);
572        assert_eq!(Complex::NEG_ONE.sqrt(), Complex::I);
573        assert_eq!(complex(0.0, 2.0).sqrt(), complex(1.0, 1.0));
574        assert_eq!(complex(0.0, -2.0).sqrt(), complex(1.0, -1.0));
575    }
576
577    #[test]
578    fn abs() {
579        for z in random_samples::<Complex>() {
580            assert_ulps_eq!(z.abs_sq(), z.abs() * z.abs());
581            assert_eq!(z.abs_sq(), z.re * z.re + z.im * z.im);
582        }
583        assert_eq!(Complex::ONE.abs(), 1.0);
584        assert_eq!(Complex::I.abs(), 1.0);
585        assert_eq!(Complex::NEG_ONE.abs(), 1.0);
586        assert_eq!(Complex::NEG_I.abs(), 1.0);
587        assert_eq!(complex(1.0, 1.0).abs(), SQRT_2);
588        assert_eq!(complex(-1.0, 1.0).abs(), SQRT_2);
589        assert_eq!(complex(-1.0, -1.0).abs(), SQRT_2);
590        assert_eq!(complex(1.0, -1.0).abs(), SQRT_2);
591    }
592
593    #[test]
594    fn conjugate() {
595        for z in random_samples::<Complex>() {
596            assert_eq!(z.conjugate().re, z.re);
597            assert_eq!(z.conjugate().im, -z.im);
598            assert_eq!(z.conjugate().conjugate(), z);
599        }
600        assert_eq!(Complex::ONE.conjugate(), Complex::ONE);
601        assert_eq!(Complex::I.conjugate(), Complex::NEG_I);
602        assert_eq!(Complex::NEG_ONE.conjugate(), Complex::NEG_ONE);
603        assert_eq!(Complex::NEG_I.conjugate(), Complex::I);
604    }
605
606    #[test]
607    fn arg() {
608        assert_eq!(Complex::ONE.arg(), 0.0);
609        assert_eq!(Complex::I.arg(), FRAC_PI_2);
610        assert_eq!(Complex::NEG_ONE.arg(), PI);
611        assert_eq!(Complex::NEG_I.arg(), -FRAC_PI_2);
612    }
613
614    #[test]
615    fn exp() {
616        for z in random_samples::<Complex>() {
617            assert_eq!(z.exp().abs, z.re.exp());
618            assert_eq!(z.exp().arg, z.im);
619            assert_ulps_eq!(z.exp().ln(), z);
620        }
621        assert_eq!(Complex::ONE.exp(), complex_polar(E, 0.0));
622        assert_eq!(Complex::I.exp(), complex_polar(1.0, 1.0));
623        assert_eq!(Complex::NEG_ONE.exp(), complex_polar(E.recip(), 0.0));
624        assert_eq!(Complex::NEG_I.exp(), complex_polar(1.0, -1.0));
625    }
626
627    #[test]
628    fn log() {
629        for z in random_samples::<Complex>() {
630            assert_eq!(z.ln().re, z.abs().ln());
631            assert_eq!(z.ln().im, z.arg());
632            assert_ulps_eq!(z.ln().exp(), z.to_polar());
633        }
634        assert_eq!(Complex::ONE.ln(), Complex::ZERO);
635        assert_eq!(Complex::I.ln(), Complex::I * FRAC_PI_2);
636        assert_eq!(Complex::NEG_ONE.ln(), Complex::I * PI);
637        assert_eq!(Complex::NEG_I.ln(), Complex::I * -FRAC_PI_2);
638
639        assert_ulps_eq!(complex(E, 0.0).ln(), Complex::ONE);
640        assert_ulps_eq!(complex(2.0, 0.0).log2(), Complex::ONE);
641        assert_ulps_eq!(complex(10.0, 0.0).log10(), Complex::ONE);
642    }
643
644    #[test]
645    fn powi() {
646        for z in random_samples::<Complex>() {
647            assert_eq!(z.powi(0), ComplexPolar::ONE);
648            assert_eq!(z.powi(1), z.to_polar());
649            for n in random_samples::<i32>() {
650                assert_eq!(z.powi(n).abs, z.abs().powi(n));
651                assert_eq!(z.powi(n).arg, z.arg() * n as f32);
652            }
653        }
654        for n in random_samples::<i32>() {
655            assert_eq!(Complex::ZERO.powi(n.abs()), ComplexPolar::ZERO);
656            assert_eq!(Complex::ONE.powi(n), ComplexPolar::ONE);
657        }
658    }
659
660    #[test]
661    fn powf() {
662        for z in random_samples::<Complex>() {
663            assert_eq!(z.powf(0.0), ComplexPolar::ONE);
664            assert_eq!(z.powf(1.0), z.to_polar());
665            for n in random_samples::<i32>() {
666                let x = n as f32 * 0.01;
667                assert_eq!(z.powf(x).abs, z.abs().powf(x));
668                assert_eq!(z.powf(x).arg, z.arg() * x);
669            }
670        }
671        for n in random_samples::<i32>() {
672            let x = n as f32 * 0.01;
673            assert_eq!(Complex::ZERO.powf(x.abs()), ComplexPolar::ZERO);
674            assert_eq!(Complex::ONE.powf(x), ComplexPolar::ONE);
675        }
676    }
677
678    // #[test]
679    // fn format_display() {
680    //     for n in random_samples::<i32>() {
681    //         let x = n as f32 * 0.01;
682    //
683    //         let z: Complex = x.into();
684    //         assert_eq!(format!("{}", z), format!("{}", x));
685    //         assert_eq!(format!("{:+}", z), format!("{:+}", x));
686    //
687    //         let z = complex(0.0, x);
688    //         assert_eq!(format!("{}", z), format!("{}i", x));
689    //         assert_eq!(format!("{:+}", z), format!("{:+}i", x));
690    //     }
691    //     assert_eq!(format!("{}", Complex::ZERO), "0");
692    //     assert_eq!(format!("{}", Complex::ONE), "1");
693    //     assert_eq!(format!("{}", Complex::NEG_ONE), "-1");
694    //     assert_eq!(format!("{}", Complex::I), "i");
695    //     assert_eq!(format!("{}", Complex::NEG_I), "-i");
696    //
697    //     assert_eq!(format!("{:+}", Complex::ZERO), "+0");
698    //     assert_eq!(format!("{:+}", -Complex::ZERO), "-0");
699    //     assert_eq!(format!("{:+}", Complex::ONE), "+1");
700    //     assert_eq!(format!("{}", 2.0 * Complex::I), "2i");
701    //     assert_eq!(format!("{}", 2.0 * Complex::NEG_I), "-2i");
702    //
703    //     assert_eq!(format!("{:+}", Complex::I), "+i");
704    //     assert_eq!(format!("{:+}", 2.0 * Complex::I), "+2i");
705    //
706    //     assert_eq!(format!("{}", complex(1.0, 1.0)), "1+i");
707    //     assert_eq!(format!("{}", complex(-1.0, 1.0)), "-1+i");
708    //     assert_eq!(format!("{}", complex(-1.0, -1.0)), "-1-i");
709    //     assert_eq!(format!("{}", complex(1.0, -1.0)), "1-i");
710    //
711    //     assert_eq!(format!("{}", complex(2.0, 2.0)), "2+2i");
712    //     assert_eq!(format!("{}", complex(-2.0, 2.0)), "-2+2i");
713    //     assert_eq!(format!("{}", complex(-2.0, -2.0)), "-2-2i");
714    //     assert_eq!(format!("{}", complex(2.0, -2.0)), "2-2i");
715    //
716    //     assert_eq!(format!("{}", complex(1.234, 1.234)), "1.234+1.234i");
717    //     assert_eq!(format!("{:.2}", complex(1.234, 1.234)), "1.23+1.23i");
718    //     assert_eq!(format!("{:+}", complex(1.234, 1.234)), "+1.234+1.234i");
719    //     assert_eq!(format!("{:+.2}", complex(1.234, 1.234)), "+1.23+1.23i");
720    // }
721}