|
|
|
@ -1,181 +1,234 @@
|
|
|
|
|
//! Complex number examples.
|
|
|
|
|
//!
|
|
|
|
|
//! The chapter presents several different variations on how one might define
|
|
|
|
|
//! arithmetic on a generic `Complex` type, so what we have here are a bunch of
|
|
|
|
|
//! isolated modules, each of which defines its own `Complex` type in its own
|
|
|
|
|
//! way. The `first_cut` module is the most well-developed.
|
|
|
|
|
//!
|
|
|
|
|
//! If you actually need a `Complex` type for real use, consider the
|
|
|
|
|
//! `num_complex` crate, whose `Complex` type is incorporated into the `num`
|
|
|
|
|
//! crate.
|
|
|
|
|
|
|
|
|
|
macro_rules! define_complex {
|
|
|
|
|
() => {
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
|
struct Complex<T> {
|
|
|
|
|
/// Real portion of the complex number
|
|
|
|
|
re: T,
|
|
|
|
|
|
|
|
|
|
/// Imaginary portion of the complex number
|
|
|
|
|
im: T
|
|
|
|
|
im: T,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
use std::ops::Mul;
|
|
|
|
|
mod first_cut {
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
|
struct Complex<T> {
|
|
|
|
|
/// Real portion of the complex number
|
|
|
|
|
re: T,
|
|
|
|
|
|
|
|
|
|
#[cfg(skip)]
|
|
|
|
|
impl Add for Complex<i32> {
|
|
|
|
|
type Output = Complex<i32>;
|
|
|
|
|
fn add(self, rhs: Self) -> Self {
|
|
|
|
|
Complex { re: self.re + rhs.re, im: self.im + rhs.im }
|
|
|
|
|
}
|
|
|
|
|
/// Imaginary portion of the complex number
|
|
|
|
|
im: T,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
|
|
|
|
|
impl<T> Add for Complex<T>
|
|
|
|
|
where T: Add<Output=T>
|
|
|
|
|
where
|
|
|
|
|
T: Add<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn add(self, rhs: Self) -> Self {
|
|
|
|
|
Complex { re: self.re + rhs.re, im: self.im + rhs.im }
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re + rhs.re,
|
|
|
|
|
im: self.im + rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(skip)]
|
|
|
|
|
impl<L, R, O> Add<Complex<R>> for Complex<L>
|
|
|
|
|
where L: Add<R, Output=O>
|
|
|
|
|
{
|
|
|
|
|
type Output = Complex<O>;
|
|
|
|
|
fn add(self, rhs: Complex<R>) -> Self::Output {
|
|
|
|
|
Complex { re: self.re + rhs.re, im: self.im + rhs.im }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(skip)]
|
|
|
|
|
impl<'a, P, Rhs> Add for &'a Complex<P>
|
|
|
|
|
where P: Add<Output=P>,
|
|
|
|
|
Rhs: AsRef<Complex<P>>
|
|
|
|
|
use std::ops::Sub;
|
|
|
|
|
|
|
|
|
|
impl<T> Sub for Complex<T>
|
|
|
|
|
where
|
|
|
|
|
T: Sub<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Complex<P>;
|
|
|
|
|
fn add(self, rhs: Rhs) -> Self::Output {
|
|
|
|
|
let rhs = rhs.as_ref();
|
|
|
|
|
Complex { re: self.re + rhs.re, im: self.im + rhs.im }
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn sub(self, rhs: Self) -> Self {
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re - rhs.re,
|
|
|
|
|
im: self.im - rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::ops::Sub;
|
|
|
|
|
use std::ops::Mul;
|
|
|
|
|
|
|
|
|
|
impl<T> Mul<Complex<T>> for Complex<T>
|
|
|
|
|
where T: Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Copy
|
|
|
|
|
impl<T> Mul for Complex<T>
|
|
|
|
|
where
|
|
|
|
|
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn mul(self, rhs: Self) -> Self {
|
|
|
|
|
Complex { re: self.re * rhs.re - self.im * rhs.im,
|
|
|
|
|
im: self.re * rhs.im + self.im * rhs.re }
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re.clone() * rhs.re.clone()
|
|
|
|
|
- (self.im.clone() * rhs.im.clone()),
|
|
|
|
|
im: self.im * rhs.re + self.re * rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test() {
|
|
|
|
|
let z = Complex { re: -2, im: 6 };
|
|
|
|
|
let c = Complex { re: 1, im: 2 };
|
|
|
|
|
assert_eq!(z + c, Complex { re: -1, im: 8 });
|
|
|
|
|
assert_eq!(z * c, Complex { re: -14, im: 2 });
|
|
|
|
|
assert_eq!(z.add(c), Complex { re: -1, im: 8 });
|
|
|
|
|
fn try_it_out() {
|
|
|
|
|
let mut z = Complex { re: 1, im: 2 };
|
|
|
|
|
let c = Complex { re: 3, im: 4 };
|
|
|
|
|
|
|
|
|
|
z = z * z + c;
|
|
|
|
|
|
|
|
|
|
std::mem::forget(z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: PartialEq> PartialEq for Complex<T> {
|
|
|
|
|
fn eq(&self, other: &Complex<T>) -> bool {
|
|
|
|
|
self.re == other.re && self.im == other.im
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_explicit() {
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
fn test_complex_eq() {
|
|
|
|
|
let x = Complex { re: 5, im: 2 };
|
|
|
|
|
let y = Complex { re: 2, im: 5 };
|
|
|
|
|
assert_eq!(x * y, Complex { re: 0, im: 29 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert_eq!(4.125f32.add(5.75), 9.875);
|
|
|
|
|
assert_eq!(10.add(20), 10 + 20);
|
|
|
|
|
impl<T: Eq> Eq for Complex<T> {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Add<Complex<f64>> for f64 {
|
|
|
|
|
type Output = Complex<f64>;
|
|
|
|
|
fn add(self, rhs: Complex<f64>) -> Complex<f64> {
|
|
|
|
|
Complex { re: rhs.re + self, im: rhs.im }
|
|
|
|
|
mod non_generic_add {
|
|
|
|
|
define_complex!();
|
|
|
|
|
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
|
|
|
|
|
impl Add for Complex<i32> {
|
|
|
|
|
type Output = Complex<i32>;
|
|
|
|
|
fn add(self, rhs: Self) -> Self {
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re + rhs.re,
|
|
|
|
|
im: self.im + rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn add_complex_to_real() {
|
|
|
|
|
assert_eq!(30f64 + Complex { re: 10.0f64, im: 20.0 },
|
|
|
|
|
Complex { re: 40.0, im: 20.0 });
|
|
|
|
|
mod somewhat_generic {
|
|
|
|
|
define_complex!();
|
|
|
|
|
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
|
|
|
|
|
impl<T> Add for Complex<T>
|
|
|
|
|
where
|
|
|
|
|
T: Add<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn add(self, rhs: Self) -> Self {
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re + rhs.re,
|
|
|
|
|
im: self.im + rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::ops::Neg;
|
|
|
|
|
|
|
|
|
|
impl<T, O> Neg for Complex<T>
|
|
|
|
|
where T: Neg<Output=O>
|
|
|
|
|
impl<T> Neg for Complex<T>
|
|
|
|
|
where
|
|
|
|
|
T: Neg<Output = T>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Complex<O>;
|
|
|
|
|
fn neg(self) -> Complex<O> {
|
|
|
|
|
Complex { re: -self.re, im: -self.im }
|
|
|
|
|
type Output = Complex<T>;
|
|
|
|
|
fn neg(self) -> Complex<T> {
|
|
|
|
|
Complex {
|
|
|
|
|
re: -self.re,
|
|
|
|
|
im: -self.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn negate_complex() {
|
|
|
|
|
let z = Complex { re: 3, im: 4 };
|
|
|
|
|
assert_eq!(-z, Complex { re: -3, im: -4 });
|
|
|
|
|
mod very_generic {
|
|
|
|
|
define_complex!();
|
|
|
|
|
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
|
|
|
|
|
impl<L, R> Add<Complex<R>> for Complex<L>
|
|
|
|
|
where
|
|
|
|
|
L: Add<R>,
|
|
|
|
|
{
|
|
|
|
|
type Output = Complex<L::Output>;
|
|
|
|
|
fn add(self, rhs: Complex<R>) -> Self::Output {
|
|
|
|
|
Complex {
|
|
|
|
|
re: self.re + rhs.re,
|
|
|
|
|
im: self.im + rhs.im,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod impl_compound {
|
|
|
|
|
define_complex!();
|
|
|
|
|
|
|
|
|
|
use std::ops::AddAssign;
|
|
|
|
|
|
|
|
|
|
impl<T> AddAssign for Complex<T>
|
|
|
|
|
where T: AddAssign<T>
|
|
|
|
|
where
|
|
|
|
|
T: AddAssign<T>,
|
|
|
|
|
{
|
|
|
|
|
fn add_assign(&mut self, rhs: Complex<T>) {
|
|
|
|
|
self.re += rhs.re;
|
|
|
|
|
self.im += rhs.im;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn compound_assignment() {
|
|
|
|
|
let mut z = Complex { re: 5, im: 6 };
|
|
|
|
|
z += Complex { re: 7, im: 8 };
|
|
|
|
|
assert_eq!(z, Complex { re: 12, im: 14 });
|
|
|
|
|
|
|
|
|
|
let mut title = "Love".to_string();
|
|
|
|
|
title += ", Actually";
|
|
|
|
|
assert_eq!(title, "Love, Actually");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: PartialEq> PartialEq for Complex<T> {
|
|
|
|
|
fn eq(&self, other: &Complex<T>) -> bool {
|
|
|
|
|
self.re == other.re && self.im == other.im
|
|
|
|
|
mod derive_partialeq {
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
|
struct Complex<T> {
|
|
|
|
|
re: T,
|
|
|
|
|
im: T,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Eq> Eq for Complex<T> { }
|
|
|
|
|
mod derive_everything {
|
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
|
struct Complex<T> {
|
|
|
|
|
/// Real portion of the complex number
|
|
|
|
|
re: T,
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn comparison() {
|
|
|
|
|
let x = Complex { re: 5, im: 2 };
|
|
|
|
|
let y = Complex { re: 2, im: 5 };
|
|
|
|
|
assert_eq!(x * y, Complex { re: 0, im: 29 });
|
|
|
|
|
/// Imaginary portion of the complex number
|
|
|
|
|
im: T,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
/// Examples from Chapter 17, Strings and Text
|
|
|
|
|
///
|
|
|
|
|
/// These use a separate, non-generic `Complex` type, for simplicity.
|
|
|
|
|
mod formatting {
|
|
|
|
|
#[test]
|
|
|
|
|
fn complex() {
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
|
struct Complex { re: f64, im: f64 }
|
|
|
|
|
|
|
|
|
|
// To make the formatting examples mesh with the rest of this file, I've adapted
|
|
|
|
|
// them to work on the type `Complex<f64>`, where the book simply defines a new
|
|
|
|
|
// non-generic `Complex` type. The only changes are adding `<f64>`, and changing
|
|
|
|
|
// the field names.
|
|
|
|
|
let third = Complex { re: -0.5, im: f64::sqrt(0.75) };
|
|
|
|
|
println!("{:?}", third);
|
|
|
|
|
|
|
|
|
|
#[cfg(skip)]
|
|
|
|
|
impl fmt::Display for Complex<f64> {
|
|
|
|
|
fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
let i_sign = if self.i < 0.0 { '-' } else { '+' };
|
|
|
|
|
write!(dest, "{} {} {}i", self.r, i_sign, f64::abs(self.i))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Complex<f64> {
|
|
|
|
|
impl fmt::Display for Complex {
|
|
|
|
|
fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
let (r, i) = (self.re, self.im);
|
|
|
|
|
if dest.alternate() {
|
|
|
|
|
let abs = f64::sqrt(r * r + i * i);
|
|
|
|
|
let angle = f64::atan2(i, r) / std::f64::consts::PI * 180.0;
|
|
|
|
|
write!(dest, "{} ∠ {}°", abs, angle)
|
|
|
|
|
} else {
|
|
|
|
|
let i_sign = if i < 0.0 { '-' } else { '+' };
|
|
|
|
|
write!(dest, "{} {} {}i", r, i_sign, f64::abs(i))
|
|
|
|
|
}
|
|
|
|
|
let im_sign = if self.im < 0.0 { '-' } else { '+' };
|
|
|
|
|
write!(dest, "{} {} {}i", self.re, im_sign, f64::abs(self.im))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn custom_display_impl() {
|
|
|
|
|
let one_twenty = Complex { re: -0.5, im: 0.866 };
|
|
|
|
|
assert_eq!(format!("{}", one_twenty),
|
|
|
|
|
"-0.5 + 0.866i");
|
|
|
|
@ -183,6 +236,28 @@ fn custom_display_impl() {
|
|
|
|
|
let two_forty = Complex { re: -0.5, im: -0.866 };
|
|
|
|
|
assert_eq!(format!("{}", two_forty),
|
|
|
|
|
"-0.5 - 0.866i");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn complex_fancy() {
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
|
struct Complex { re: f64, im: f64 }
|
|
|
|
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Complex {
|
|
|
|
|
fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
let (re, im) = (self.re, self.im);
|
|
|
|
|
if dest.alternate() {
|
|
|
|
|
let abs = f64::sqrt(re * re + im * im);
|
|
|
|
|
let angle = f64::atan2(im, re) / std::f64::consts::PI * 180.0;
|
|
|
|
|
write!(dest, "{} ∠ {}°", abs, angle)
|
|
|
|
|
} else {
|
|
|
|
|
let im_sign = if im < 0.0 { '-' } else { '+' };
|
|
|
|
|
write!(dest, "{} {} {}i", re, im_sign, f64::abs(im))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let ninety = Complex { re: 0.0, im: 2.0 };
|
|
|
|
|
assert_eq!(format!("{}", ninety),
|
|
|
|
@ -190,3 +265,4 @@ fn custom_display_impl() {
|
|
|
|
|
assert_eq!(format!("{:#}", ninety),
|
|
|
|
|
"2 ∠ 90°");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|