feat(eval): add rounding functions
added: - `round(num, dec)` -> rounds `num` to `dec` amount of decimal places with `RoundingStrategy::MidpointAwayFromZero` - `floor(num)` -> floors `num` to the nearest integer - `ceil(num)` -> ceils `num` to the nearest integer fixed: - use proper function types instead of function pointers for the util functions in the builtin function registry
This commit is contained in:
2 files changed
+40
-4
No files matched your search
+40
-2
@@ -2,6 +2,8 @@ use crate::math::context::Context;
|
||||
use crate::math::types::Expression;
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal::MathematicalOps;
|
||||
use rust_decimal::RoundingStrategy;
|
||||
use rust_decimal::dec;
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
impl Context {
|
||||
@@ -30,17 +32,53 @@ impl Context {
|
||||
self.register_function("atan", |params: Vec<Expression>| {
|
||||
map_decimal(¶ms[0], |d| map_f64(&d, |f| f.atan()))
|
||||
});
|
||||
self.register_function("round", |params: Vec<Expression>| {
|
||||
let decimal = if params.len() == 2 {
|
||||
if let Some(d) = get_decimal(¶ms[1]) {
|
||||
d
|
||||
} else {
|
||||
dec!(0)
|
||||
}
|
||||
} else {
|
||||
dec!(0)
|
||||
}
|
||||
.to_u32()
|
||||
.expect("unable to parse decimal number");
|
||||
|
||||
map_decimal(¶ms[0], |d| {
|
||||
d.round_dp_with_strategy(decimal, RoundingStrategy::MidpointAwayFromZero)
|
||||
})
|
||||
});
|
||||
self.register_function("floor", |params: Vec<Expression>| {
|
||||
map_decimal(¶ms[0], |d| d.floor())
|
||||
});
|
||||
self.register_function("ceil", |params: Vec<Expression>| {
|
||||
map_decimal(¶ms[0], |d| d.ceil())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn map_decimal(expr: &Expression, f: fn(Decimal) -> Decimal) -> Expression {
|
||||
fn get_decimal(expr: &Expression) -> Option<Decimal> {
|
||||
match expr {
|
||||
Expression::Number(d) => Some(*d),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_decimal<F>(expr: &Expression, f: F) -> Expression
|
||||
where
|
||||
F: Fn(Decimal) -> Decimal,
|
||||
{
|
||||
match expr {
|
||||
Expression::Number(d) => Expression::Number(f(*d)),
|
||||
_ => panic!("expected decimal"),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_f64(decimal: &Decimal, f: fn(f64) -> f64) -> Decimal {
|
||||
fn map_f64<F>(decimal: &Decimal, f: F) -> Decimal
|
||||
where
|
||||
F: Fn(f64) -> f64,
|
||||
{
|
||||
let num = decimal.to_f64().expect("unable to unwrap decimal");
|
||||
let num = f(num);
|
||||
Decimal::from_f64_retain(num).expect("unable to wrap decimal")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use crate::math::types::Expression;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
||||
Reference in new issue
Block a user