Skip to content

Instantly share code, notes, and snippets.

@LongJohnCoder
Forked from fanf2/complex.rs
Created December 6, 2020 23:13
Show Gist options
  • Select an option

  • Save LongJohnCoder/98512fa6f3d5d1162b8dd91fa93f6b13 to your computer and use it in GitHub Desktop.

Select an option

Save LongJohnCoder/98512fa6f3d5d1162b8dd91fa93f6b13 to your computer and use it in GitHub Desktop.
complex numbers with vanishing zeroes
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