Info

Implementing an operator:

use std::ops::Add;

struct S(u32);

impl Add<S> for S {
    type Output = S;

    fn add(self, rhs: S) -> Self::Output {
        S(self.0 + rhs.0)
    }
}

Taking a generic:

use std::{fmt::Debug, ops::Add};

fn f<T: Debug + Add<Output = u32>>(x: T, y: T) {
    println!("{}", x + y);
}

Assert:

fn main() {
    assert!(true);
    assert_eq!(5, 5);
    assert_ne!(10, 11);
}

Problem

Define and implement code for a datatype Complex that represents a complex number. The type will keep its data as f64. The type has to implement the following:

  • associated function new that takes 2 arguments, each with a generic type, that will be used to convert and initialize the type;
  • associated function conjugate that returns the conjugate of the number;
  • implement From for i32 and f64 for the type; the number will be the real part, and the imaginary part will be 0;
  • implement Add, Sub, Mul that is generic over any type that can be converted to Complex;
  • implement Neg;
  • implement Display that respects the rules shown below;

The following code must compile and print ok! when run. Do not modify it.

fn eq_rel(x: f64, y: f64) -> bool {
    (x - y).abs() < 0.001
}
// This is a macro that panics if 2 floats are not equal using an epsilon.
// You are not required to understand it yet, just to use it.
macro_rules! assert_eq_rel {
    ($x:expr, $y: expr) => {
        let x = $x as f64;
        let y = $y as f64;
        let r = eq_rel(x, y);
        assert!(r, "{} != {}", x, y);
    };
}

fn main() {
    let a = Complex::new(1.0, 2.0);
    assert_eq_rel!(a.real, 1);
    assert_eq_rel!(a.imag, 2);

    let b = Complex::new(2.0, 3);
    let c = a + b;
    assert_eq_rel!(c.real, 3);
    assert_eq_rel!(c.imag, 5);

    let d = c - a;
    assert_eq!(b, d);

    let e = (a * d).conjugate();
    assert_eq_rel!(e.imag, -7);

    let f = (a + b - d) * c;
    assert_eq!(f, Complex::new(-7, 11));

    // Note: .to_string() uses Display to format the type
    assert_eq!(Complex::new(1, 2).to_string(), "1+2i");
    assert_eq!(Complex::new(1, -2).to_string(), "1-2i");
    assert_eq!(Complex::new(0, 5).to_string(), "5i");
    assert_eq!(Complex::new(7, 0).to_string(), "7");
    assert_eq!(Complex::new(0, 0).to_string(), "0");

    let h = Complex::new(-4, -5);
    let i = h - (h + 5) * 2.0;
    assert_eq_rel!(i.real, -6);

    let j = -i + i;
    assert_eq_rel!(j.real, 0);
    assert_eq_rel!(j.imag, 0);

    println!("ok!");
}

Math help: link.

Bonus

Also implement AddAssign, SubAssign, MulAssign, and any other operator or special trait that makes sense for the type.