From fc21756785a157aa1340259964c13aa636028324 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 13 Feb 2021 23:25:22 +0800 Subject: [PATCH] Add rounding functions to Decimal numbers. --- RELEASES.md | 1 + src/packages/math_basic.rs | 114 ++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 0d01c4e7..89d2fd3b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -9,6 +9,7 @@ Bug fixes * Empty statements (i.e. statements with only one `;`) now parse correctly and no longer hang. * `continue`, `break` and `return` statements no longer panic inside a `try .. catch` block. +* `round` function for `f64` is now implemented correctly. Breaking changes ---------------- diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index a6a82c42..ff485154 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -19,6 +19,9 @@ use crate::stdlib::format; #[cfg(feature = "decimal")] use rust_decimal::Decimal; +#[cfg(feature = "decimal")] +use super::arithmetic::make_err; + #[allow(dead_code)] #[cfg(feature = "only_i32")] pub const MAX_INT: INT = i32::MAX; @@ -228,7 +231,7 @@ mod float_functions { } #[rhai_fn(name = "round", get = "round")] pub fn round(x: FLOAT) -> FLOAT { - x.ceil() + x.round() } #[rhai_fn(name = "int", get = "int")] pub fn int(x: FLOAT) -> FLOAT { @@ -311,7 +314,114 @@ mod decimal_functions { } #[rhai_fn(name = "round", get = "round")] pub fn round(x: Decimal) -> Decimal { - x.ceil() + x.round() + } + #[rhai_fn(return_raw)] + pub fn round_dp(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp(dp as u32))) + } + #[rhai_fn(return_raw)] + pub fn round_up(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundUp, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_down(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundDown, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_half_up(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundHalfUp, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_half_down(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundHalfDown, + ))) } #[rhai_fn(name = "int", get = "int")] pub fn int(x: Decimal) -> Decimal {