177 lines
5.9 KiB
Rust
177 lines
5.9 KiB
Rust
use crate::{
|
|
calc_result::CalcResult,
|
|
expressions::{parser::Node, token::Error, types::CellReferenceIndex},
|
|
model::Model,
|
|
};
|
|
|
|
use super::transcendental::{bessel_i, bessel_j, bessel_k, bessel_y, erf};
|
|
// https://root.cern/doc/v610/TMath_8cxx_source.html
|
|
|
|
// Notice that the parameters for Bessel functions in Excel and here have inverted order
|
|
// EXCEL_BESSEL(x, n) => bessel(n, x)
|
|
|
|
impl Model {
|
|
pub(crate) fn fn_besseli(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = match self.get_number_no_bools(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = n.trunc() as i32;
|
|
let result = bessel_i(n, x);
|
|
if result.is_infinite() || result.is_nan() {
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
pub(crate) fn fn_besselj(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = match self.get_number_no_bools(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = n.trunc() as i32;
|
|
if n < 0 {
|
|
// In Excel this ins #NUM!
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
let result = bessel_j(n, x);
|
|
if result.is_infinite() || result.is_nan() {
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
|
|
pub(crate) fn fn_besselk(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = match self.get_number_no_bools(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = n.trunc() as i32;
|
|
let result = bessel_k(n, x);
|
|
if result.is_infinite() || result.is_nan() {
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
|
|
pub(crate) fn fn_bessely(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = match self.get_number_no_bools(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let n = n.trunc() as i32;
|
|
if n < 0 {
|
|
// In Excel this ins #NUM!
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
let result = bessel_y(n, x);
|
|
if result.is_infinite() || result.is_nan() {
|
|
return CalcResult::Error {
|
|
error: Error::NUM,
|
|
origin: cell,
|
|
message: "Invalid parameter for Bessel function".to_string(),
|
|
};
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
|
|
pub(crate) fn fn_erf(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if !(1..=2).contains(&args.len()) {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if args.len() == 2 {
|
|
let y = match self.get_number_no_bools(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
CalcResult::Number(erf(y) - erf(x))
|
|
} else {
|
|
CalcResult::Number(erf(x))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn fn_erfprecise(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 1 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
};
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
CalcResult::Number(erf(x))
|
|
}
|
|
|
|
pub(crate) fn fn_erfc(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 1 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
};
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
CalcResult::Number(1.0 - erf(x))
|
|
}
|
|
|
|
pub(crate) fn fn_erfcprecise(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 1 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
};
|
|
let x = match self.get_number_no_bools(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
CalcResult::Number(1.0 - erf(x))
|
|
}
|
|
}
|