complex/
complex.rs

1use std::fmt::{Display, Formatter};
2use std::io::{stdin, stdout, Write};
3use std::num::ParseFloatError;
4use std::str::FromStr;
5
6use thiserror::Error;
7
8use expressions::eval;
9use expressions::eval::Eval;
10
11/// A complex number that uses an f64 for its real and imaginary part.
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct Complex {
14    pub real: f64,
15    pub imag: f64,
16}
17
18impl Complex {
19    /// Helper function to create complex numbers.
20    pub fn new(real: f64, imag: f64) -> Self {
21        Self { real, imag }
22    }
23}
24
25impl Display for Complex {
26    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27        match (self.real != 0., self.imag != 0.) {
28            (true, true) => f.write_str(&format!(
29                "{} {} {}i",
30                self.real,
31                if self.imag.is_sign_positive() {
32                    '+'
33                } else {
34                    '-'
35                },
36                self.imag.abs()
37            )),
38            (true, false) => f.write_str(&format!("{}", self.real)),
39            (false, true) => f.write_str(&format!("{}i", self.imag)),
40            (false, false) => f.write_str("0"),
41        }
42    }
43}
44
45/// An error that occurs when a successfully parsed expression can not be evaluated successfully.
46#[derive(Error, Debug, PartialEq)]
47pub enum ComplexEvalErr {
48    /// An operator that is not supported on complex numbers was used.
49    #[error("use of unsupported operator")]
50    OperatorNotSupported,
51}
52
53/// Implementing eval allows the type to be used as type to evaluate expressions with. To implement
54/// eval, [Clone] and [eval::EvalParse] should also be implemented on the type.
55impl Eval for Complex {
56    type ErrEval = ComplexEvalErr;
57
58    fn eq(self, other: Self) -> Result<Self, Self::ErrEval> {
59        match self == other {
60            true => Ok(Self::new(1., 0.)),
61            false => Ok(Self::new(0., 0.)),
62        }
63    }
64
65    fn neq(self, other: Self) -> Result<Self, Self::ErrEval> {
66        match self != other {
67            true => Ok(Self::new(1., 0.)),
68            false => Ok(Self::new(0., 0.)),
69        }
70    }
71
72    fn gte(self, _other: Self) -> Result<Self, Self::ErrEval> {
73        Err(ComplexEvalErr::OperatorNotSupported)
74    }
75
76    fn gt(self, _other: Self) -> Result<Self, Self::ErrEval> {
77        Err(ComplexEvalErr::OperatorNotSupported)
78    }
79
80    fn lte(self, _other: Self) -> Result<Self, Self::ErrEval> {
81        Err(ComplexEvalErr::OperatorNotSupported)
82    }
83
84    fn lt(self, _other: Self) -> Result<Self, Self::ErrEval> {
85        Err(ComplexEvalErr::OperatorNotSupported)
86    }
87
88    fn and(self, _other: Self) -> Result<Self, Self::ErrEval> {
89        Err(ComplexEvalErr::OperatorNotSupported)
90    }
91
92    fn or(self, _other: Self) -> Result<Self, Self::ErrEval> {
93        Err(ComplexEvalErr::OperatorNotSupported)
94    }
95
96    fn bit_and(self, _other: Self) -> Result<Self, Self::ErrEval> {
97        Err(ComplexEvalErr::OperatorNotSupported)
98    }
99
100    fn bit_or(self, _other: Self) -> Result<Self, Self::ErrEval> {
101        Err(ComplexEvalErr::OperatorNotSupported)
102    }
103
104    fn add(self, other: Self) -> Result<Self, Self::ErrEval> {
105        Ok(Self {
106            real: self.real + other.real,
107            imag: self.imag + other.imag,
108        })
109    }
110
111    fn sub(self, other: Self) -> Result<Self, Self::ErrEval> {
112        Ok(Self {
113            real: self.real - other.real,
114            imag: self.imag - other.imag,
115        })
116    }
117
118    fn mul(self, other: Self) -> Result<Self, Self::ErrEval> {
119        Ok(Self {
120            real: self.real * other.real - self.imag * other.imag,
121            imag: self.real * other.imag * 2.,
122        })
123    }
124
125    fn div(self, other: Self) -> Result<Self, Self::ErrEval> {
126        let divisor = other.real * other.real + other.imag * other.imag;
127        Ok(Self {
128            real: (self.real * other.real + self.imag * other.imag) / divisor,
129            imag: (self.imag * other.real - self.real * other.imag) / divisor,
130        })
131    }
132
133    fn rem(self, _: Self) -> Result<Self, Self::ErrEval> {
134        Err(ComplexEvalErr::OperatorNotSupported)
135    }
136
137    fn exp(self, _: Self) -> Result<Self, Self::ErrEval> {
138        Err(ComplexEvalErr::OperatorNotSupported)
139    }
140
141    fn plus(self) -> Result<Self, Self::ErrEval> {
142        Ok(self)
143    }
144
145    fn minus(self) -> Result<Self, Self::ErrEval> {
146        Ok(Self {
147            real: -self.real,
148            imag: -self.imag,
149        })
150    }
151
152    fn not(self) -> Result<Self, Self::ErrEval> {
153        Err(ComplexEvalErr::OperatorNotSupported)
154    }
155
156    fn bit_not(self) -> Result<Self, Self::ErrEval> {
157        Err(ComplexEvalErr::OperatorNotSupported)
158    }
159}
160
161/// An error that occurs when a complex number literal could not be parsed.
162#[derive(Error, Debug, PartialEq)]
163pub enum ComplexParseErr {
164    /// The float literal could not be parsed regardless of whether or not 'i' was present.
165    #[error("{0}")]
166    ParseFloatErr(#[from] ParseFloatError),
167}
168
169/// [eval::EvalParse] is automatically implemented for any type that implements [FromStr] where the
170/// returned error implements [std::error::Error].
171impl FromStr for Complex {
172    type Err = ComplexParseErr;
173
174    /// Parses the complex number from a string. Formats such as `a + bi` need not be supported:
175    /// these values can be achieved with an binary addition of two literals `a` and `bi`.
176    fn from_str(s: &str) -> Result<Self, Self::Err> {
177        // Remove the 'i' from the string if it is an imaginary number.
178        let (substr, is_imag) = if s.chars().last().map_or(false, |v| v == 'i') {
179            (&s[0..(s.len() - 1)], true)
180        } else {
181            (s, false)
182        };
183
184        let magnitude = substr.parse()?;
185        Ok(Self {
186            real: if !is_imag { magnitude } else { 0. },
187            imag: if is_imag { magnitude } else { 0. },
188        })
189    }
190}
191
192#[test]
193fn test_complex() {
194    assert_eq!(
195        eval::<Complex>("-1i + 23 - 394"),
196        Ok(Complex::new(-371., -1.))
197    );
198    assert_eq!(
199        eval::<Complex>("-1i + 23 + (2i - --1i)"),
200        Ok(Complex::new(23., 0.))
201    );
202    assert_eq!(
203        eval::<Complex>("(-1i + 23 + 2i - --1i) * (1 - 3i) * (5i)"),
204        Ok(Complex::new(690., 230.))
205    );
206    assert_eq!(eval::<Complex>("10 * 10"), Ok(Complex::new(100., 0.)),);
207    assert_eq!(eval::<Complex>("10i * 10i"), Ok(Complex::new(-100., 0.)),);
208    assert_eq!(
209        eval::<Complex>("-1i + 23 - 390 / 39"),
210        Ok(Complex::new(13., -1.))
211    );
212    assert_eq!(eval::<Complex>("-1i / 1i"), Ok(Complex::new(-1., 0.)));
213
214    assert!(eval::<Complex>("-1ii").is_err());
215    assert!(eval::<Complex>("i").is_err());
216    assert!(eval::<Complex>("").is_err());
217}
218
219fn main() {
220    let mut buf = String::new();
221    loop {
222        print!("Input: ");
223        stdout().flush().expect("could not flush stdout");
224        stdin()
225            .read_line(&mut buf)
226            .expect("could not read from stdin: ");
227
228        match eval::<Complex>(&buf) {
229            Ok(val) => println!("Result: {}", val),
230            Err(err) => eprintln!("Error: {}", err),
231        };
232        buf.clear();
233    }
234}