-
-
Save LongJohnCoder/98512fa6f3d5d1162b8dd91fa93f6b13 to your computer and use it in GitHub Desktop.
complex numbers with vanishing zeroes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::ops::{Add, Mul, Neg, Sub}; | |
| pub type Num = f64; | |
| #[derive(Clone, Copy, Debug, Default, PartialEq)] | |
| pub struct Zero; | |
| impl From<Zero> for Num { | |
| fn from(_: Zero) -> Num { | |
| 0.0 | |
| } | |
| } | |
| pub type Prod<A, B> = <A as Mul<B>>::Output; | |
| pub trait Sum { | |
| type Output; | |
| } | |
| macro_rules! sum_for { | |
| ( $($list:ty),+ => $output:ty ) => { | |
| impl Sum for ($($list),+) { | |
| type Output = $output; | |
| } | |
| }; | |
| } | |
| sum_for!(Zero, Zero => Zero); | |
| sum_for!(Zero, Num => Num); | |
| sum_for!(Num, Zero => Num); | |
| sum_for!(Num, Num => Num); | |
| #[derive(Clone, Copy, Debug, PartialEq)] | |
| struct Complex<R, I>(R, I); | |
| type ComplexNum = Complex<Num, Num>; | |
| #[cfg(test)] | |
| mod tests { | |
| use crate::*; | |
| use std::mem::{size_of, size_of_val}; | |
| #[test] | |
| fn complex() { | |
| let re = Complex(1.0, Zero); | |
| assert_eq!(size_of_val(&re), size_of::<Num>()); | |
| let im = Complex(Zero, 1.0); | |
| assert_eq!(size_of_val(&im), size_of::<Num>()); | |
| let c = re + im; | |
| assert_eq!(size_of_val(&c), size_of::<Num>() * 2); | |
| let re2 = re + re; | |
| assert_eq!(size_of_val(&re2), size_of::<Num>()); | |
| let im2 = im + im; | |
| assert_eq!(size_of_val(&im2), size_of::<Num>()); | |
| assert_eq!(re2, 2.0 * re); | |
| assert_eq!(im2, im * 2.0); | |
| assert_eq!(im * im, -re); | |
| assert_eq!(re * im, im); | |
| assert_eq!(c * im, im - re); | |
| assert_eq!(c, 1.0 + im); | |
| } | |
| } | |
| macro_rules! complex_from { | |
| ($R:ty, $I:ty) => { | |
| impl From<Complex<$R, $I>> for ComplexNum { | |
| fn from(c: Complex<$R, $I>) -> Self { | |
| let Complex(r, i) = c; | |
| Complex(r.into(), i.into()) | |
| } | |
| } | |
| }; | |
| } | |
| complex_from!(Zero, Zero); | |
| complex_from!(Zero, Num); | |
| complex_from!(Num, Zero); | |
| trait CMul<A, B> { | |
| fn re(_: A, _: B) -> Self; | |
| fn im(_: A, _: B) -> Self; | |
| } | |
| impl<A, B> CMul<A, B> for Zero { | |
| fn re(_: A, _: B) -> Self { | |
| Zero | |
| } | |
| fn im(_: A, _: B) -> Self { | |
| Zero | |
| } | |
| } | |
| impl<Ar, Ai, Br, Bi> CMul<Complex<Ar, Ai>, Complex<Br, Bi>> for Num | |
| where | |
| ComplexNum: From<Complex<Ar, Ai>>, | |
| ComplexNum: From<Complex<Br, Bi>>, | |
| { | |
| fn re(a: Complex<Ar, Ai>, b: Complex<Br, Bi>) -> Self { | |
| let Complex(ar, ai) = ComplexNum::from(a); | |
| let Complex(br, bi) = ComplexNum::from(b); | |
| ar * br - ai * bi | |
| } | |
| fn im(a: Complex<Ar, Ai>, b: Complex<Br, Bi>) -> Self { | |
| let Complex(ar, ai) = ComplexNum::from(a); | |
| let Complex(br, bi) = ComplexNum::from(b); | |
| ar * bi + ai * br | |
| } | |
| } | |
| impl<Ar, Ai, Br, Bi> Mul<Complex<Br, Bi>> for Complex<Ar, Ai> | |
| where | |
| Ar: Mul<Br>, | |
| Ar: Mul<Bi>, | |
| Ai: Mul<Br>, | |
| Ai: Mul<Bi>, | |
| (Prod<Ar, Br>, Prod<Ai, Bi>): Sum, | |
| <(Prod<Ar, Br>, Prod<Ai, Bi>) as Sum>::Output: | |
| CMul<Complex<Ar, Ai>, Complex<Br, Bi>>, | |
| (Prod<Ar, Bi>, Prod<Ai, Br>): Sum, | |
| <(Prod<Ar, Bi>, Prod<Ai, Br>) as Sum>::Output: | |
| CMul<Complex<Ar, Ai>, Complex<Br, Bi>>, | |
| Complex<Ar, Ai>: Copy + Into<ComplexNum>, | |
| Complex<Br, Bi>: Copy + Into<ComplexNum>, | |
| { | |
| #[allow(clippy::type_complexity)] | |
| type Output = | |
| Complex<<(Prod<Ar, Br>, Prod<Ai, Bi>) as Sum>::Output, | |
| <(Prod<Ar, Bi>, Prod<Ai, Br>) as Sum>::Output>; | |
| fn mul(self, other: Complex<Br, Bi>) -> Self::Output { | |
| Complex(CMul::re(self, other), CMul::im(self, other)) | |
| } | |
| } | |
| impl<R, I> Mul<Num> for Complex<R, I> | |
| where | |
| R: Mul<Num>, | |
| I: Mul<Num>, | |
| { | |
| type Output = Complex<<R as Mul<Num>>::Output, <I as Mul<Num>>::Output>; | |
| fn mul(self, b: Num) -> Self::Output { | |
| let Complex(ar, ai) = self; | |
| Complex(ar * b, ai * b) | |
| } | |
| } | |
| impl<R, I> Mul<Complex<R, I>> for Num | |
| where | |
| Num: Mul<R>, | |
| Num: Mul<I>, | |
| { | |
| type Output = Complex<<Num as Mul<R>>::Output, <Num as Mul<I>>::Output>; | |
| fn mul(self, b: Complex<R, I>) -> Self::Output { | |
| let Complex(br, bi) = b; | |
| Complex(self * br, self * bi) | |
| } | |
| } | |
| impl Mul<Zero> for Num { | |
| type Output = Zero; | |
| fn mul(self, _: Zero) -> Zero { | |
| Zero | |
| } | |
| } | |
| impl Mul<Num> for Zero { | |
| type Output = Zero; | |
| fn mul(self, _: Num) -> Zero { | |
| Zero | |
| } | |
| } | |
| impl Mul<Zero> for Zero { | |
| type Output = Zero; | |
| fn mul(self, _: Zero) -> Zero { | |
| Zero | |
| } | |
| } | |
| impl<Ar, Ai, Br, Bi> Add<Complex<Br, Bi>> for Complex<Ar, Ai> | |
| where | |
| Ar: Add<Br>, | |
| Ai: Add<Bi>, | |
| { | |
| type Output = Complex<<Ar as Add<Br>>::Output, <Ai as Add<Bi>>::Output>; | |
| fn add(self, b: Complex<Br, Bi>) -> Self::Output { | |
| let a: Complex<Ar, Ai> = self; | |
| let Complex(ar, ai) = a; | |
| let Complex(br, bi) = b; | |
| Complex(ar + br, ai + bi) | |
| } | |
| } | |
| impl<R, I> Add<Num> for Complex<R, I> | |
| where | |
| R: Add<Num>, | |
| { | |
| type Output = Complex<<R as Add<Num>>::Output, I>; | |
| fn add(self, b: Num) -> Self::Output { | |
| let Complex(ar, ai) = self; | |
| Complex(ar + b, ai) | |
| } | |
| } | |
| impl<R, I> Add<Complex<R, I>> for Num | |
| where | |
| Num: Add<R>, | |
| { | |
| type Output = Complex<<Num as Add<R>>::Output, I>; | |
| fn add(self, b: Complex<R, I>) -> Self::Output { | |
| let Complex(br, bi) = b; | |
| Complex(self + br, bi) | |
| } | |
| } | |
| impl Add<Zero> for Num { | |
| type Output = Num; | |
| fn add(self, _: Zero) -> Num { | |
| self | |
| } | |
| } | |
| impl Add<Num> for Zero { | |
| type Output = Num; | |
| fn add(self, other: Num) -> Num { | |
| other | |
| } | |
| } | |
| impl Add<Zero> for Zero { | |
| type Output = Zero; | |
| fn add(self, _: Zero) -> Zero { | |
| Zero | |
| } | |
| } | |
| impl<Ar, Ai, Br, Bi> Sub<Complex<Br, Bi>> for Complex<Ar, Ai> | |
| where | |
| Ar: Sub<Br>, | |
| Ai: Sub<Bi>, | |
| { | |
| type Output = Complex<<Ar as Sub<Br>>::Output, <Ai as Sub<Bi>>::Output>; | |
| fn sub(self, b: Complex<Br, Bi>) -> Self::Output { | |
| let a: Complex<Ar, Ai> = self; | |
| let Complex(ar, ai) = a; | |
| let Complex(br, bi) = b; | |
| Complex(ar - br, ai - bi) | |
| } | |
| } | |
| impl<R, I> Sub<Num> for Complex<R, I> | |
| where | |
| R: Sub<Num>, | |
| { | |
| type Output = Complex<<R as Sub<Num>>::Output, I>; | |
| fn sub(self, b: Num) -> Self::Output { | |
| let Complex(ar, ai) = self; | |
| Complex(ar - b, ai) | |
| } | |
| } | |
| impl<R, I> Sub<Complex<R, I>> for Num | |
| where | |
| Num: Sub<R>, | |
| { | |
| type Output = Complex<<Num as Sub<R>>::Output, I>; | |
| fn sub(self, b: Complex<R, I>) -> Self::Output { | |
| let Complex(br, bi) = b; | |
| Complex(self - br, bi) | |
| } | |
| } | |
| impl Sub<Zero> for Num { | |
| type Output = Num; | |
| fn sub(self, _: Zero) -> Num { | |
| self | |
| } | |
| } | |
| impl Sub<Num> for Zero { | |
| type Output = Num; | |
| fn sub(self, other: Num) -> Num { | |
| -other | |
| } | |
| } | |
| impl Sub<Zero> for Zero { | |
| type Output = Zero; | |
| fn sub(self, _: Zero) -> Zero { | |
| Zero | |
| } | |
| } | |
| impl<R, I> Neg for Complex<R, I> | |
| where | |
| R: Neg<Output = R>, | |
| I: Neg<Output = I>, | |
| { | |
| type Output = Self; | |
| fn neg(self) -> Self { | |
| let Complex(r, i) = self; | |
| Complex(-r, -i) | |
| } | |
| } | |
| impl Neg for Zero { | |
| type Output = Self; | |
| fn neg(self) -> Self { | |
| self | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment