UPDATE: Adds 56 functions in the Statistical section
Uses statrs for numerical functions REFACTOR: Put statistical functions on its own module This might seem counter-intuitive but the wasm build after this refactor is 1528 bytes smaller :)
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
67ef3bcf87
commit
6822505602
124
base/src/functions/statistical/log_normal.rs
Normal file
124
base/src/functions/statistical/log_normal.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use statrs::distribution::{Continuous, ContinuousCDF, LogNormal};
|
||||
|
||||
use crate::expressions::types::CellReferenceIndex;
|
||||
use crate::{
|
||||
calc_result::CalcResult, expressions::parser::Node, expressions::token::Error, model::Model,
|
||||
};
|
||||
|
||||
impl Model {
|
||||
pub(crate) fn fn_log_norm_dist(
|
||||
&mut self,
|
||||
args: &[Node],
|
||||
cell: CellReferenceIndex,
|
||||
) -> CalcResult {
|
||||
if args.len() != 4 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
|
||||
let x = match self.get_number_no_bools(&args[0], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let mean = match self.get_number_no_bools(&args[1], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let std_dev = match self.get_number_no_bools(&args[2], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let cumulative = match self.get_boolean(&args[3], cell) {
|
||||
Ok(b) => b,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
// Excel domain checks
|
||||
if x <= 0.0 || std_dev <= 0.0 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.DIST".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let dist = match LogNormal::new(mean, std_dev) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.DIST".to_string(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let result = if cumulative { dist.cdf(x) } else { dist.pdf(x) };
|
||||
|
||||
if !result.is_finite() {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.DIST".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
CalcResult::Number(result)
|
||||
}
|
||||
|
||||
pub(crate) fn fn_log_norm_inv(
|
||||
&mut self,
|
||||
args: &[Node],
|
||||
cell: CellReferenceIndex,
|
||||
) -> CalcResult {
|
||||
use statrs::distribution::{ContinuousCDF, LogNormal};
|
||||
|
||||
if args.len() != 3 {
|
||||
return CalcResult::new_args_number_error(cell);
|
||||
}
|
||||
|
||||
let p = match self.get_number_no_bools(&args[0], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let mean = match self.get_number_no_bools(&args[1], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
let std_dev = match self.get_number_no_bools(&args[2], cell) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
// Excel domain checks
|
||||
if p <= 0.0 || p >= 1.0 || std_dev <= 0.0 {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.INV".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let dist = match LogNormal::new(mean, std_dev) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.INV".to_string(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let result = dist.inverse_cdf(p);
|
||||
|
||||
if !result.is_finite() {
|
||||
return CalcResult::Error {
|
||||
error: Error::NUM,
|
||||
origin: cell,
|
||||
message: "Invalid parameter for LOGNORM.INV".to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
CalcResult::Number(result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user