aboutsummaryrefslogtreecommitdiff
path: root/src/math/complex.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/complex.rs')
-rw-r--r--src/math/complex.rs191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/math/complex.rs b/src/math/complex.rs
new file mode 100644
index 0000000..5b95df4
--- /dev/null
+++ b/src/math/complex.rs
@@ -0,0 +1,191 @@
+use std::f64::consts::E;
+use std::num::ParseFloatError;
+use std::str::FromStr;
+
+#[derive(Clone, Copy, Default, Debug)]
+pub struct Complex {
+ pub real: f64,
+ pub imag: f64,
+}
+
+impl Complex {
+ pub fn new(real: f64, imag: f64) -> Self {
+ Self { real, imag }
+ }
+
+ pub fn is_real(&self) -> bool {
+ self.imag == 0.0
+ }
+
+ pub fn abs(&self) -> f64 {
+ (self.real.powi(2) + self.imag.powi(2)).sqrt()
+ }
+
+ pub fn pow(&self, rhs: Self) -> Self {
+ if self.is_real() && rhs.is_real() {
+ Complex::new(self.real.powf(rhs.real), 0.0)
+ } else {
+ let r = self.abs();
+ let x = (self.imag / self.real).atan();
+ let lnr = r.ln();
+ let alpha = lnr * rhs.imag + x * rhs.real;
+ let e_exp = E.powf(lnr * rhs.real - rhs.imag * x);
+ Complex::new(e_exp * alpha.cos(), e_exp * alpha.sin())
+ }
+ }
+
+ pub fn sqrt(&self) -> Self {
+ self.pow(Complex::new(0.5, 0.0))
+ }
+
+ pub fn cos(&self) -> Self {
+ let e: Complex = E.into();
+ let i = Complex::new(0.0, 1.0);
+
+ Complex::new(e.pow(&i * self).real, 0.0)
+ }
+
+ pub fn sin(&self) -> Self {
+ let e: Complex = E.into();
+ let i = Complex::new(0.0, 1.0);
+
+ Complex::new(e.pow(&i * self).imag, 0.0)
+ }
+
+ pub fn tan(&self) -> Self {
+ self.sin() / self.cos()
+ }
+}
+
+impl std::fmt::Display for Complex {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ if self.imag == 0.0 {
+ write!(f, "{}", self.real)
+ } else if self.real == 0.0 {
+ if self.imag == 1.0 {
+ write!(f, "i")
+ } else {
+ write!(f, "{}i", self.imag)
+ }
+ } else if self.imag == 1.0 {
+ write!(f, "{} + i", self.real)
+ } else {
+ write!(f, "{} + {}i", self.real, self.imag)
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct ComplexParseError;
+
+impl From<ParseFloatError> for ComplexParseError {
+ fn from(_: ParseFloatError) -> Self {
+ Self {}
+ }
+}
+
+impl FromStr for Complex {
+ type Err = ComplexParseError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut c = Complex::default();
+ let s = s.replace(' ', "");
+ if s.contains('+') {
+ let (a, b) = s.split_once('+').unwrap();
+ if a.contains('i') {
+ c.imag = a[..a.len() - 1].parse()?;
+ c.real = b.parse()?;
+ } else {
+ c.real = a.parse()?;
+ c.imag = b[..b.len() - 1].parse()?;
+ }
+ } else if s.contains('i') {
+ if s.len() == 1 {
+ c.imag = 1.0;
+ } else {
+ c.imag = s[..s.len() - 1].parse()?;
+ }
+ } else {
+ c.real = s.parse()?;
+ }
+
+ Ok(c)
+ }
+}
+
+impl From<f64> for Complex {
+ fn from(val: f64) -> Self {
+ Complex::new(val, 0.0)
+ }
+}
+
+impl std::ops::Add for &Complex {
+ type Output = Complex;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ *self + *rhs
+ }
+}
+
+impl std::ops::Add for Complex {
+ type Output = Complex;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ Complex::new(self.real + rhs.real, self.imag + rhs.imag)
+ }
+}
+
+impl std::ops::Sub for &Complex {
+ type Output = Complex;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ *self - *rhs
+ }
+}
+
+impl std::ops::Sub for Complex {
+ type Output = Complex;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ Complex::new(self.real - rhs.real, self.imag - rhs.imag)
+ }
+}
+
+impl std::ops::Mul for &Complex {
+ type Output = Complex;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ *self * *rhs
+ }
+}
+
+impl std::ops::Mul for Complex {
+ type Output = Complex;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ Complex::new(
+ self.real * rhs.real - self.imag * rhs.imag,
+ self.real * rhs.imag + self.imag * rhs.real,
+ )
+ }
+}
+
+impl std::ops::Div for &Complex {
+ type Output = Complex;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ *self / *rhs
+ }
+}
+
+impl std::ops::Div for Complex {
+ type Output = Complex;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ let z = rhs.real * rhs.real + rhs.imag * rhs.imag;
+ Complex::new(
+ (self.real * rhs.real + self.imag * rhs.imag) / z,
+ (self.imag * rhs.real - self.real * rhs.imag) / z,
+ )
+ }
+}