UPDATE: Dump of initial files
This commit is contained in:
793
base/src/functions/engineering/complex.rs
Normal file
793
base/src/functions/engineering/complex.rs
Normal file
@@ -0,0 +1,793 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
calc_result::{CalcResult, CellReference},
|
||||
expressions::{
|
||||
lexer::util::get_tokens,
|
||||
parser::Node,
|
||||
token::{Error, OpSum, TokenType},
|
||||
},
|
||||
model::Model,
|
||||
number_format::to_precision,
|
||||
};
|
||||
|
||||
/// This implements all functions with complex arguments in the standard
|
||||
/// NOTE: If performance is ever needed we should have a new entry in CalcResult,
|
||||
/// So this functions will return CalcResult::Complex(x,y, Suffix)
|
||||
/// and not having to parse it over and over again.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Suffix {
|
||||
I,
|
||||
J,
|
||||
}
|
||||
|
||||
impl fmt::Display for Suffix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Suffix::I => write!(f, "i"),
|
||||
Suffix::J => write!(f, "j"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Complex {
|
||||
x: f64,
|
||||
y: f64,
|
||||
suffix: Suffix,
|
||||
}
|
||||
|
||||
impl fmt::Display for Complex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let x = to_precision(self.x, 15);
|
||||
let y = to_precision(self.y, 15);
|
||||
let suffix = &self.suffix;
|
||||
// it is a bit weird what Excel does but it seems it uses general notation for
|
||||
// numbers > 1e-20 and scientific notation for the rest
|
||||
let y_str = if y.abs() <= 9e-20 {
|
||||
format!("{:E}", y)
|
||||
} else if y == 1.0 {
|
||||
"".to_string()
|
||||
} else if y == -1.0 {
|
||||
"-".to_string()
|
||||
} else {
|
||||
format!("{}", y)
|
||||
};
|
||||
let x_str = if x.abs() <= 9e-20 {
|
||||
format!("{:E}", x)
|
||||
} else {
|
||||
format!("{}", x)
|
||||
};
|
||||
if y == 0.0 && x == 0.0 {
|
||||
write!(f, "0")
|
||||
} else if y == 0.0 {
|
||||
write!(f, "{x_str}")
|
||||
} else if x == 0.0 {
|
||||
write!(f, "{y_str}{suffix}")
|
||||
} else if y > 0.0 {
|
||||
write!(f, "{x_str}+{y_str}{suffix}")
|
||||
} else {
|
||||
write!(f, "{x_str}{y_str}{suffix}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_complex_number(s: &str) -> Result<(f64, f64, Suffix), String> {
|
||||
// Check for i, j, -i, -j
|
||||
let (sign, s) = match s.strip_prefix('-') {
|
||||
Some(r) => (-1.0, r),
|
||||
None => (1.0, s),
|
||||
};
|
||||
match s {
|
||||
"i" => return Ok((0.0, sign * 1.0, Suffix::I)),
|
||||
"j" => return Ok((0.0, sign * 1.0, Suffix::J)),
|
||||
_ => {
|
||||
// Let it go
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: This is an overuse
|
||||
let tokens = get_tokens(s);
|
||||
|
||||
// There has to be 1, 2 3, or 4 tokens
|
||||
// number
|
||||
// number suffix
|
||||
// number1+suffix
|
||||
// number1+number2 suffix
|
||||
|
||||
match tokens.len() {
|
||||
1 => {
|
||||
// Real number
|
||||
let number1 = match tokens[0].token {
|
||||
TokenType::Number(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
// i is the default
|
||||
Ok((sign * number1, 0.0, Suffix::I))
|
||||
}
|
||||
2 => {
|
||||
// number2 i
|
||||
let number2 = match tokens[0].token {
|
||||
TokenType::Number(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let suffix = match &tokens[1].token {
|
||||
TokenType::Ident(w) => match w.as_str() {
|
||||
"i" => Suffix::I,
|
||||
"j" => Suffix::J,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
},
|
||||
_ => {
|
||||
return Err(format!("Not a complex number: {s}"));
|
||||
}
|
||||
};
|
||||
Ok((0.0, sign * number2, suffix))
|
||||
}
|
||||
3 => {
|
||||
let number1 = match tokens[0].token {
|
||||
TokenType::Number(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let operation = match &tokens[1].token {
|
||||
TokenType::Addition(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let suffix = match &tokens[2].token {
|
||||
TokenType::Ident(w) => match w.as_str() {
|
||||
"i" => Suffix::I,
|
||||
"j" => Suffix::J,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
},
|
||||
_ => {
|
||||
return Err(format!("Not a complex number: {s}"));
|
||||
}
|
||||
};
|
||||
let number2 = if matches!(operation, OpSum::Minus) {
|
||||
-1.0
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
Ok((sign * number1, number2, suffix))
|
||||
}
|
||||
4 => {
|
||||
let number1 = match tokens[0].token {
|
||||
TokenType::Number(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let operation = match &tokens[1].token {
|
||||
TokenType::Addition(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let mut number2 = match tokens[2].token {
|
||||
TokenType::Number(f) => f,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
};
|
||||
let suffix = match &tokens[3].token {
|
||||
TokenType::Ident(w) => match w.as_str() {
|
||||
"i" => Suffix::I,
|
||||
"j" => Suffix::J,
|
||||
_ => return Err(format!("Not a complex number: {s}")),
|
||||
},
|
||||
_ => {
|
||||
return Err(format!("Not a complex number: {s}"));
|
||||
}
|
||||
};
|
||||
if matches!(operation, OpSum::Minus) {
|
||||
number2 = -number2
|
||||
}
|
||||
Ok((sign * number1, number2, suffix))
|
||||
}
|
||||
_ => Err(format!("Not a complex number: {s}")),
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn get_complex_number(
|
||||
&mut self,
|
||||
node: &Node,
|
||||
cell: CellReference,
|
||||
) -> Result<(f64, f64, Suffix), CalcResult> {
|
||||
let value = match self.get_string(node, cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return Err(s),
|
||||
};
|
||||
if value.is_empty() {
|
||||
return Ok((0.0, 0.0, Suffix::I));
|
||||
}
|
||||
match parse_complex_number(&value) {
|
||||
Ok(s) => Ok(s),
|
||||
Err(message) => Err(CalcResult::new_error(Error::NUM, cell, message)),
|
||||
}
|
||||
}
|
||||
// COMPLEX(real_num, i_num, [suffix])
|
||||
pub(crate) fn fn_complex(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if !(2..=3).contains(&args.len()) {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let x = match self.get_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let y = match self.get_number(&args[1], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let suffix = if args.len() == 3 {
|
||||
match self.get_string(&args[2], cell) {
|
||||
Ok(s) => {
|
||||
if s == "i" || s.is_empty() {
|
||||
Suffix::I
|
||||
} else if s == "j" {
|
||||
Suffix::J
|
||||
} else {
|
||||
return CalcResult::new_error(
|
||||
Error::VALUE,
|
||||
cell,
|
||||
"Invalid suffix".to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(s) => return s,
|
||||
}
|
||||
} else {
|
||||
Suffix::I
|
||||
};
|
||||
|
||||
let complex = Complex { x, y, suffix };
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imabs(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, _) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
CalcResult::Number(f64::sqrt(x * x + y * y))
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imaginary(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (_, y, _) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
CalcResult::Number(y)
|
||||
}
|
||||
pub(crate) fn fn_imargument(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, _) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
if x == 0.0 && y == 0.0 {
|
||||
return CalcResult::new_error(Error::DIV, cell, "Division by zero".to_string());
|
||||
}
|
||||
let angle = f64::atan2(y, x);
|
||||
CalcResult::Number(angle)
|
||||
}
|
||||
pub(crate) fn fn_imconjugate(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let complex = Complex { x, y: -y, suffix };
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imcos(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let value = match self.get_string(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let (x, y, suffix) = match parse_complex_number(&value) {
|
||||
Ok(s) => s,
|
||||
Err(message) => return CalcResult::new_error(Error::NUM, cell, message),
|
||||
};
|
||||
|
||||
let complex = Complex {
|
||||
x: x.cos() * y.cosh(),
|
||||
y: -x.sin() * y.sinh(),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imcosh(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let value = match self.get_string(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let (x, y, suffix) = match parse_complex_number(&value) {
|
||||
Ok(s) => s,
|
||||
Err(message) => return CalcResult::new_error(Error::NUM, cell, message),
|
||||
};
|
||||
|
||||
let complex = Complex {
|
||||
x: x.cosh() * y.cos(),
|
||||
y: x.sinh() * y.sin(),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imcot(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let value = match self.get_string(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let (x, y, suffix) = match parse_complex_number(&value) {
|
||||
Ok(s) => s,
|
||||
Err(message) => return CalcResult::new_error(Error::NUM, cell, message),
|
||||
};
|
||||
|
||||
if x == 0.0 && y != 0.0 {
|
||||
let complex = Complex {
|
||||
x: 0.0,
|
||||
y: -1.0 / y.tanh(),
|
||||
suffix,
|
||||
};
|
||||
return CalcResult::String(complex.to_string());
|
||||
} else if y == 0.0 {
|
||||
let complex = Complex {
|
||||
x: 1.0 / x.tan(),
|
||||
y: 0.0,
|
||||
suffix,
|
||||
};
|
||||
return CalcResult::String(complex.to_string());
|
||||
}
|
||||
|
||||
let x_cot = 1.0 / x.tan();
|
||||
let y_coth = 1.0 / y.tanh();
|
||||
|
||||
let t = x_cot * x_cot + y_coth * y_coth;
|
||||
let x = (x_cot * y_coth * y_coth - x_cot) / t;
|
||||
let y = (-x_cot * x_cot * y_coth - y_coth) / t;
|
||||
|
||||
if x.is_infinite() || y.is_infinite() || x.is_nan() || y.is_nan() {
|
||||
return CalcResult::new_error(Error::NUM, cell, "Invalid operation".to_string());
|
||||
}
|
||||
|
||||
let complex = Complex { x, y, suffix };
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imcsc(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let value = match self.get_string(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let (x, y, suffix) = match parse_complex_number(&value) {
|
||||
Ok(s) => s,
|
||||
Err(message) => return CalcResult::new_error(Error::NUM, cell, message),
|
||||
};
|
||||
let x_cos = x.cos();
|
||||
let x_sin = x.sin();
|
||||
|
||||
let y_cosh = y.cosh();
|
||||
let y_sinh = y.sinh();
|
||||
|
||||
let t = x_sin * x_sin * y_cosh * y_cosh + x_cos * x_cos * y_sinh * y_sinh;
|
||||
|
||||
let complex = Complex {
|
||||
x: x_sin * y_cosh / t,
|
||||
y: -x_cos * y_sinh / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imcsch(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let value = match self.get_string(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(s) => return s,
|
||||
};
|
||||
let (x, y, suffix) = match parse_complex_number(&value) {
|
||||
Ok(s) => s,
|
||||
Err(message) => return CalcResult::new_error(Error::NUM, cell, message),
|
||||
};
|
||||
let x_cosh = x.cosh();
|
||||
let x_sinh = x.sinh();
|
||||
|
||||
let y_cos = y.cos();
|
||||
let y_sin = y.sin();
|
||||
|
||||
let t = x_sinh * x_sinh * y_cos * y_cos + x_cosh * x_cosh * y_sin * y_sin;
|
||||
|
||||
let complex = Complex {
|
||||
x: x_sinh * y_cos / t,
|
||||
y: -x_cosh * y_sin / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imdiv(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 2 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x1, y1, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let (x2, y2, suffix2) = match self.get_complex_number(&args[1], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
if suffix != suffix2 {
|
||||
return CalcResult::new_error(Error::VALUE, cell, "Different suffixes".to_string());
|
||||
}
|
||||
let t = x2 * x2 + y2 * y2;
|
||||
if t == 0.0 {
|
||||
return CalcResult::new_error(Error::NUM, cell, "Invalid".to_string());
|
||||
}
|
||||
let complex = Complex {
|
||||
x: (x1 * x2 + y1 * y2) / t,
|
||||
y: (-x1 * y2 + y1 * x2) / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imexp(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let complex = Complex {
|
||||
x: x.exp() * y.cos(),
|
||||
y: x.exp() * y.sin(),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imln(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let r = f64::sqrt(x * x + y * y);
|
||||
let a = f64::atan2(y, x);
|
||||
|
||||
let complex = Complex {
|
||||
x: r.ln(),
|
||||
y: a,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imlog10(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let r = f64::sqrt(x * x + y * y);
|
||||
let a = f64::atan2(y, x);
|
||||
|
||||
let complex = Complex {
|
||||
x: r.log10(),
|
||||
y: a * f64::log10(f64::exp(1.0)),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imlog2(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let r = f64::sqrt(x * x + y * y);
|
||||
let a = f64::atan2(y, x);
|
||||
|
||||
let complex = Complex {
|
||||
x: r.log2(),
|
||||
y: a * f64::log2(f64::exp(1.0)),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
// IMPOWER(imnumber, power)
|
||||
// If $(r, \theta)$ is the polar representation the formula is:
|
||||
// $$ x = r^n*\cos(n\dot\theta), y = r^n*\csin(n\dot\theta) $
|
||||
pub(crate) fn fn_impower(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 2 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let n = match self.get_number_no_bools(&args[1], cell) {
|
||||
Ok(f) => f,
|
||||
Err(s) => return s,
|
||||
};
|
||||
|
||||
// if n == n.trunc() && n < 10.0 {
|
||||
// // for small powers we compute manually
|
||||
// let (mut x0, mut y0) = (x, y);
|
||||
// for _ in 1..(n.trunc() as i32) {
|
||||
// (x0, y0) = (x0 * x - y0 * y, x0 * y + y0 * x);
|
||||
// }
|
||||
// let complex = Complex {
|
||||
// x: x0,
|
||||
// y: y0,
|
||||
// suffix,
|
||||
// };
|
||||
// return CalcResult::String(complex.to_string());
|
||||
// };
|
||||
|
||||
let r = f64::sqrt(x * x + y * y);
|
||||
let a = f64::atan2(y, x);
|
||||
|
||||
let x = r.powf(n) * f64::cos(a * n);
|
||||
let y = r.powf(n) * f64::sin(a * n);
|
||||
|
||||
if x.is_infinite() || y.is_infinite() || x.is_nan() || y.is_nan() {
|
||||
return CalcResult::new_error(Error::NUM, cell, "Invalid operation".to_string());
|
||||
}
|
||||
|
||||
let complex = Complex { x, y, suffix };
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_improduct(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 2 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
|
||||
let (x1, y1, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let (x2, y2, suffix2) = match self.get_complex_number(&args[1], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
if suffix != suffix2 {
|
||||
return CalcResult::new_error(Error::VALUE, cell, "Different suffixes".to_string());
|
||||
}
|
||||
let complex = Complex {
|
||||
x: x1 * x2 - y1 * y2,
|
||||
y: x1 * y2 + y1 * x2,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imreal(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, _, _) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
CalcResult::Number(x)
|
||||
}
|
||||
pub(crate) fn fn_imsec(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let x_cos = x.cos();
|
||||
let x_sin = x.sin();
|
||||
|
||||
let y_cosh = y.cosh();
|
||||
let y_sinh = y.sinh();
|
||||
|
||||
let t = x_cos * x_cos * y_cosh * y_cosh + x_sin * x_sin * y_sinh * y_sinh;
|
||||
|
||||
let complex = Complex {
|
||||
x: x_cos * y_cosh / t,
|
||||
y: x_sin * y_sinh / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imsech(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let x_cosh = x.cosh();
|
||||
let x_sinh = x.sinh();
|
||||
|
||||
let y_cos = y.cos();
|
||||
let y_sin = y.sin();
|
||||
|
||||
let t = x_cosh * x_cosh * y_cos * y_cos + x_sinh * x_sinh * y_sin * y_sin;
|
||||
|
||||
let complex = Complex {
|
||||
x: x_cosh * y_cos / t,
|
||||
y: -x_sinh * y_sin / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imsin(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let complex = Complex {
|
||||
x: x.sin() * y.cosh(),
|
||||
y: x.cos() * y.sinh(),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imsinh(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let complex = Complex {
|
||||
x: x.sinh() * y.cos(),
|
||||
y: x.cosh() * y.sin(),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imsqrt(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let r = f64::sqrt(x * x + y * y).sqrt();
|
||||
let a = f64::atan2(y, x);
|
||||
|
||||
let complex = Complex {
|
||||
x: r * f64::cos(a / 2.0),
|
||||
y: r * f64::sin(a / 2.0),
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
pub(crate) fn fn_imsub(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 2 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x1, y1, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let (x2, y2, suffix2) = match self.get_complex_number(&args[1], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
if suffix != suffix2 {
|
||||
return CalcResult::new_error(Error::VALUE, cell, "Different suffixes".to_string());
|
||||
}
|
||||
let complex = Complex {
|
||||
x: x1 - x2,
|
||||
y: y1 - y2,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imsum(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 2 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x1, y1, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
let (x2, y2, suffix2) = match self.get_complex_number(&args[1], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
if suffix != suffix2 {
|
||||
return CalcResult::new_error(Error::VALUE, cell, "Different suffixes".to_string());
|
||||
}
|
||||
let complex = Complex {
|
||||
x: x1 + x2,
|
||||
y: y1 + y2,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn fn_imtan(&mut self, args: &[Node], cell: CellReference) -> CalcResult {
|
||||
if args.len() != 1 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
let (x, y, suffix) = match self.get_complex_number(&args[0], cell) {
|
||||
Ok(s) => s,
|
||||
Err(error) => return error,
|
||||
};
|
||||
|
||||
let x_tan = x.tan();
|
||||
let y_tanh = y.tanh();
|
||||
|
||||
let t = 1.0 + x_tan * x_tan * y_tanh * y_tanh;
|
||||
|
||||
let complex = Complex {
|
||||
x: (x_tan - x_tan * y_tanh * y_tanh) / t,
|
||||
y: (y_tanh + x_tan * x_tan * y_tanh) / t,
|
||||
suffix,
|
||||
};
|
||||
CalcResult::String(complex.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::functions::engineering::complex::Suffix;
|
||||
|
||||
use super::parse_complex_number as parse;
|
||||
|
||||
#[test]
|
||||
fn test_parse_complex() {
|
||||
assert_eq!(parse("1+2i"), Ok((1.0, 2.0, Suffix::I)));
|
||||
assert_eq!(parse("2i"), Ok((0.0, 2.0, Suffix::I)));
|
||||
assert_eq!(parse("7.5"), Ok((7.5, 0.0, Suffix::I)));
|
||||
assert_eq!(parse("-7.5"), Ok((-7.5, 0.0, Suffix::I)));
|
||||
assert_eq!(parse("7-5i"), Ok((7.0, -5.0, Suffix::I)));
|
||||
assert_eq!(parse("i"), Ok((0.0, 1.0, Suffix::I)));
|
||||
assert_eq!(parse("7+i"), Ok((7.0, 1.0, Suffix::I)));
|
||||
assert_eq!(parse("7-i"), Ok((7.0, -1.0, Suffix::I)));
|
||||
assert_eq!(parse("-i"), Ok((0.0, -1.0, Suffix::I)));
|
||||
assert_eq!(parse("0"), Ok((0.0, 0.0, Suffix::I)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user