Rust重载运算符之复数四则运算的实现
作者:Hann Yang
基本概念
复数定义
由实数部分和虚数部分所组成的数,形如a+bi 。
其中a、b为实数,i 为“虚数单位”,i² = -1,即虚数单位的平方等于-1。
a、b分别叫做复数a+bi的实部和虚部。
- 当b=0时,a+bi=a 为实数;
- 当b≠0时,a+bi 又称虚数;
- 当b≠0、a=0时,bi 称为纯虚数。
实数和虚数都是复数的子集。如同实数可以在数轴上表示一样复数也可以在平面上表示,复数x+yi以坐标点(x,y)来表示。表示复数的平面称为“复平面”。
复数相等
两个复数不能比较大小,但当个两个复数的实部和虚部分别相等时,即表示两个复数相等。
共轭复数
如果两个复数的实部相等,虚部互为相反数,那么这两个复数互为共轭复数。
复数的模
复数的实部与虚部的平方和的正的平方根的值称为该复数的模,数学上用与绝对值“|z|”相同的符号来表示。虽然从定义上是不相同的,但两者的物理意思都表示“到原点的距离”。
复数的四则运算
加法(减法)法则
复数的加法法则:设z1=a+bi,z2 =c+di是任意两个复数。两者和的实部是原来两个复数实部的和,它的虚部是原来两个虚部的和。两个复数的和依然是复数。
即(a+bi)±(c+di)=(a±c)+(b±d)
乘法法则
复数的乘法法则:把两个复数相乘,类似两个多项式相乘,结果中i²=-1,把实部与虚部分别合并。两个复数的积仍然是一个复数。
即(a+bi)(c+di)=(ac-bd)+(bc+ad)i
除法法则
数除法法则:满足(c+di)(x+yi)=(a+bi)的复数x+yi(x,y∈R)叫复数a+bi除以复数c+di的商。
运算方法:可以把除法换算成乘法做,将分子分母同时乘上分母的共轭复数,再用乘法运算。
即(a+bi)/(c+di)=(a+bi)(c-di)/(c*c+d*d)=[(ac+bd)+(bc-ad)i]/(c*c+d*d)
复数的Rust代码实现
结构定义
Rust语言中,没有像python一样内置complex复数数据类型,我们可以用两个浮点数分别表示复数的实部和虚部,自定义一个结构数据类型,表示如下:
struct Complex {
real: f64,
imag: f64,
}
示例代码:
#[derive(Debug)] struct Complex { real: f64, imag: f64, } impl Complex { fn new(real: f64, imag: f64) -> Self { Complex { real, imag } } } fn main() { let z = Complex::new(3.0, 4.0); println!("{:?}", z); println!("{} + {}i", z.real, z.imag); }
注意:#[derive(Debug)] 自动定义了复数结构的输出格式,如以上代码输出如下:
Complex { real: 3.0, imag: 4.0 }
3 + 4i
重载四则运算
复数数据结构不能直接用加减乘除来做复数运算,需要导入标准库ops的运算符:
use std::ops::{Add, Sub, Mul, Div, Neg};
Add, Sub, Mul, Div, Neg 分别表示加减乘除以及相反数,类似C++或者python语言中“重载运算符”的概念。
根据复数的运算法则,写出对应代码:
fn add(self, other: Complex) -> Complex { Complex { real: self.real + other.real, imag: self.imag + other.imag, } } fn sub(self, other: Complex) -> Complex { Complex { real: self.real - other.real, imag: self.imag - other.imag, } } fn mul(self, other: Complex) -> Complex { let real = self.real * other.real - self.imag * other.imag; let imag = self.real * other.imag + self.imag * other.real; Complex { real, imag } } fn div(self, other: Complex) -> Complex { let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag); let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag); Complex { real, imag } } fn neg(self) -> Complex { Complex { real: -self.real, imag: -self.imag, } }
Rust 重载运算的格式,请见如下示例代码:
use std::ops::{Add, Sub, Mul, Div, Neg}; #[derive(Clone, Debug, PartialEq)] struct Complex { real: f64, imag: f64, } impl Complex { fn new(real: f64, imag: f64) -> Self { Complex { real, imag } } fn conj(&self) -> Self { Complex { real: self.real, imag: -self.imag } } fn abs(&self) -> f64 { (self.real * self.real + self.imag * self.imag).sqrt() } } fn abs(z: Complex) -> f64 { (z.real * z.real + z.imag * z.imag).sqrt() } impl Add<Complex> for Complex { type Output = Complex; fn add(self, other: Complex) -> Complex { Complex { real: self.real + other.real, imag: self.imag + other.imag, } } } impl Sub<Complex> for Complex { type Output = Complex; fn sub(self, other: Complex) -> Complex { Complex { real: self.real - other.real, imag: self.imag - other.imag, } } } impl Mul<Complex> for Complex { type Output = Complex; fn mul(self, other: Complex) -> Complex { let real = self.real * other.real - self.imag * other.imag; let imag = self.real * other.imag + self.imag * other.real; Complex { real, imag } } } impl Div<Complex> for Complex { type Output = Complex; fn div(self, other: Complex) -> Complex { let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag); let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag); Complex { real, imag } } } impl Neg for Complex { type Output = Complex; fn neg(self) -> Complex { Complex { real: -self.real, imag: -self.imag, } } } fn main() { let z1 = Complex::new(2.0, 3.0); let z2 = Complex::new(3.0, 4.0); let z3 = Complex::new(3.0, -4.0); // 复数的四则运算 let complex_add = z1.clone() + z2.clone(); println!("{:?} + {:?} = {:?}", z1, z2, complex_add); let complex_sub = z1.clone() - z2.clone(); println!("{:?} - {:?} = {:?}", z1, z2, complex_sub); let complex_mul = z1.clone() * z2.clone(); println!("{:?} * {:?} = {:?}", z1, z2, complex_mul); let complex_div = z2.clone() / z3.clone(); println!("{:?} / {:?} = {:?}", z1, z2, complex_div); // 对比两个复数是否相等 println!("{:?}", z1 == z2); // 共轭复数 println!("{:?}", z2 == z3.conj()); // 复数的相反数 println!("{:?}", z2 == -z3.clone() + Complex::new(6.0,0.0)); // 复数的模 println!("{}", z1.abs()); println!("{}", z2.abs()); println!("{}", abs(z3)); }
输出:
Complex { real: 2.0, imag: 3.0 } + Complex { real: 3.0, imag: 4.0 } = Complex { real: 5.0, imag: 7.0 }
Complex { real: 2.0, imag: 3.0 } - Complex { real: 3.0, imag: 4.0 } = Complex { real: -1.0, imag: -1.0 }
Complex { real: 2.0, imag: 3.0 } * Complex { real: 3.0, imag: 4.0 } = Complex { real: -6.0, imag: 17.0 }
Complex { real: 2.0, imag: 3.0 } / Complex { real: 3.0, imag: 4.0 } = Complex { real: -0.28, imag: 0.96 }
false
true
true
3.605551275463989
5
5
示例代码中,同时还定义了复数的模 abs(),共轭复数 conj()。
两个复数的相等比较 z1 == z2,需要 #[derive(PartialEq)] 支持。
自定义 trait Display
复数结构的原始 Debug trait 表达的输出格式比较繁复,如:
Complex { real: 2.0, imag: 3.0 } + Complex { real: 3.0, imag: 4.0 } = Complex { real: 5.0, imag: 7.0 }
想要输出和数学中相同的表达(如 a + bi),需要自定义一个 Display trait,代码如下:
impl std::fmt::Display for Complex { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { if self.imag == 0.0 { formatter.write_str(&format!("{}", self.real)) } else { let (abs, sign) = if self.imag > 0.0 { (self.imag, "+" ) } else { (-self.imag, "-" ) }; if abs == 1.0 { formatter.write_str(&format!("({} {} i)", self.real, sign)) } else { formatter.write_str(&format!("({} {} {}i)", self.real, sign, abs)) } } } }
输出格式分三种情况:虚部为0,正数和负数。另外当虚部绝对值为1时省略1仅输出i虚数单位。
完整代码如下:
use std::ops::{Add, Sub, Mul, Div, Neg}; #[derive(Clone, PartialEq)] struct Complex { real: f64, imag: f64, } impl std::fmt::Display for Complex { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { if self.imag == 0.0 { formatter.write_str(&format!("{}", self.real)) } else { let (abs, sign) = if self.imag > 0.0 { (self.imag, "+" ) } else { (-self.imag, "-" ) }; if abs == 1.0 { formatter.write_str(&format!("({} {} i)", self.real, sign)) } else { formatter.write_str(&format!("({} {} {}i)", self.real, sign, abs)) } } } } impl Complex { fn new(real: f64, imag: f64) -> Self { Complex { real, imag } } fn conj(&self) -> Self { Complex { real: self.real, imag: -self.imag } } fn abs(&self) -> f64 { (self.real * self.real + self.imag * self.imag).sqrt() } } fn abs(z: Complex) -> f64 { (z.real * z.real + z.imag * z.imag).sqrt() } impl Add<Complex> for Complex { type Output = Complex; fn add(self, other: Complex) -> Complex { Complex { real: self.real + other.real, imag: self.imag + other.imag, } } } impl Sub<Complex> for Complex { type Output = Complex; fn sub(self, other: Complex) -> Complex { Complex { real: self.real - other.real, imag: self.imag - other.imag, } } } impl Mul<Complex> for Complex { type Output = Complex; fn mul(self, other: Complex) -> Complex { let real = self.real * other.real - self.imag * other.imag; let imag = self.real * other.imag + self.imag * other.real; Complex { real, imag } } } impl Div<Complex> for Complex { type Output = Complex; fn div(self, other: Complex) -> Complex { let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag); let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag); Complex { real, imag } } } impl Neg for Complex { type Output = Complex; fn neg(self) -> Complex { Complex { real: -self.real, imag: -self.imag, } } } fn main() { let z1 = Complex::new(2.0, 3.0); let z2 = Complex::new(3.0, 4.0); let z3 = Complex::new(3.0, -4.0); // 复数的四则运算 let complex_add = z1.clone() + z2.clone(); println!("{} + {} = {}", z1, z2, complex_add); let z = Complex::new(1.5, 0.5); println!("{} + {} = {}", z, z, z.clone() + z.clone()); let complex_sub = z1.clone() - z2.clone(); println!("{} - {} = {}", z1, z2, complex_sub); let complex_sub = z1.clone() - z1.clone(); println!("{} - {} = {}", z1, z1, complex_sub); let complex_mul = z1.clone() * z2.clone(); println!("{} * {} = {}", z1, z2, complex_mul); let complex_mul = z2.clone() * z3.clone(); println!("{} * {} = {}", z2, z3, complex_mul); let complex_div = z2.clone() / z3.clone(); println!("{} / {} = {}", z1, z2, complex_div); let complex_div = Complex::new(1.0,0.0) / z2.clone(); println!("1 / {} = {}", z2, complex_div); // 对比两个复数是否相等 println!("{:?}", z1 == z2); // 共轭复数 println!("{:?}", z2 == z3.conj()); // 复数的相反数 println!("{:?}", z2 == -z3.clone() + Complex::new(6.0,0.0)); // 复数的模 println!("{}", z1.abs()); println!("{}", z2.abs()); println!("{}", abs(z3)); }
输出:
(2 + 3i) + (3 + 4i) = (5 + 7i)
(1.5 + 0.5i) + (1.5 + 0.5i) = (3 + i)
(2 + 3i) - (3 + 4i) = (-1 - i)
(2 + 3i) - (2 + 3i) = 0
(2 + 3i) * (3 + 4i) = (-6 + 17i)
(3 + 4i) * (3 - 4i) = 25
(2 + 3i) / (3 + 4i) = (-0.28 + 0.96i)
1 / (3 + 4i) = (0.12 - 0.16i)
false
true
true
3.605551275463989
5
5
小结
如此,复数的四则运算基本都实现了,当然复数还有三角表示式和指数表示式,根据它们的数学定义写出相当代码应该不是很难。有了复数三角式,就能方便地定义出复数的开方运算,有空可以写写这方面的代码。
到此这篇关于Rust重载运算符之复数四则运算的实现的文章就介绍到这了,更多相关Rust运算符内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!