more fixes, still not done yet
This commit is contained in:
@@ -3,7 +3,7 @@ use rust_decimal::prelude::*;
|
|||||||
use rust_decimal::MathematicalOps;
|
use rust_decimal::MathematicalOps;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// Global precision setting for the current Steel execution context
|
// Global precision setting for the current Steel execution context
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static PRECISION_CONTEXT: std::cell::RefCell<Option<u32>> = std::cell::RefCell::new(None);
|
static PRECISION_CONTEXT: std::cell::RefCell<Option<u32>> = std::cell::RefCell::new(None);
|
||||||
}
|
}
|
||||||
@@ -105,44 +105,6 @@ pub fn decimal_div(a: String, b: String) -> Result<String, String> {
|
|||||||
Ok(format_result(a_dec / b_dec))
|
Ok(format_result(a_dec / b_dec))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precision-specific operations (explicit precision override)
|
|
||||||
pub fn decimal_add_p(a: String, b: String, precision: u32) -> Result<String, String> {
|
|
||||||
let a_dec = parse_decimal(&a)?;
|
|
||||||
let b_dec = parse_decimal(&b)?;
|
|
||||||
let result = a_dec + b_dec;
|
|
||||||
|
|
||||||
Ok(result.round_dp(precision).to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decimal_sub_p(a: String, b: String, precision: u32) -> Result<String, String> {
|
|
||||||
let a_dec = parse_decimal(&a)?;
|
|
||||||
let b_dec = parse_decimal(&b)?;
|
|
||||||
let result = a_dec - b_dec;
|
|
||||||
|
|
||||||
Ok(result.round_dp(precision).to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decimal_mul_p(a: String, b: String, precision: u32) -> Result<String, String> {
|
|
||||||
let a_dec = parse_decimal(&a)?;
|
|
||||||
let b_dec = parse_decimal(&b)?;
|
|
||||||
let result = a_dec * b_dec;
|
|
||||||
|
|
||||||
Ok(result.round_dp(precision).to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decimal_div_p(a: String, b: String, precision: u32) -> Result<String, String> {
|
|
||||||
let a_dec = parse_decimal(&a)?;
|
|
||||||
let b_dec = parse_decimal(&b)?;
|
|
||||||
|
|
||||||
if b_dec.is_zero() {
|
|
||||||
return Err("Division by zero".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = a_dec / b_dec;
|
|
||||||
|
|
||||||
Ok(result.round_dp(precision).to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Precision control functions
|
// Precision control functions
|
||||||
pub fn set_precision(precision: u32) -> String {
|
pub fn set_precision(precision: u32) -> String {
|
||||||
if precision > 28 {
|
if precision > 28 {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ impl FunctionRegistry {
|
|||||||
/// Register all decimal math functions with the Steel VM
|
/// Register all decimal math functions with the Steel VM
|
||||||
pub fn register_all(vm: &mut Engine) {
|
pub fn register_all(vm: &mut Engine) {
|
||||||
Self::register_basic_arithmetic(vm);
|
Self::register_basic_arithmetic(vm);
|
||||||
Self::register_precision_arithmetic(vm);
|
|
||||||
Self::register_precision_control(vm);
|
Self::register_precision_control(vm);
|
||||||
Self::register_advanced_math(vm);
|
Self::register_advanced_math(vm);
|
||||||
Self::register_trigonometric(vm);
|
Self::register_trigonometric(vm);
|
||||||
@@ -29,14 +28,6 @@ impl FunctionRegistry {
|
|||||||
vm.register_fn("decimal-div", decimal_div);
|
vm.register_fn("decimal-div", decimal_div);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register precision-specific arithmetic functions
|
|
||||||
pub fn register_precision_arithmetic(vm: &mut Engine) {
|
|
||||||
vm.register_fn("decimal-add-p", decimal_add_p);
|
|
||||||
vm.register_fn("decimal-sub-p", decimal_sub_p);
|
|
||||||
vm.register_fn("decimal-mul-p", decimal_mul_p);
|
|
||||||
vm.register_fn("decimal-div-p", decimal_div_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register precision control functions
|
/// Register precision control functions
|
||||||
pub fn register_precision_control(vm: &mut Engine) {
|
pub fn register_precision_control(vm: &mut Engine) {
|
||||||
vm.register_fn("set-precision", set_precision);
|
vm.register_fn("set-precision", set_precision);
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ fn test_decimal_precision_edge_cases(#[case] a: &str, #[case] b: &str, #[case] e
|
|||||||
// Test scientific notation
|
// Test scientific notation
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case("1e2", "2e1", "120")]
|
#[case("1e2", "2e1", "120")]
|
||||||
#[case("1.5e2", "2.3e1", "173")]
|
#[case("1.5e2", "2.3e1", "173.0")]
|
||||||
fn test_scientific_notation(#[case] a: &str, #[case] b: &str, #[case] expected: &str) {
|
fn test_scientific_notation(#[case] a: &str, #[case] b: &str, #[case] expected: &str) {
|
||||||
let result = decimal_add(a.to_string(), b.to_string()).unwrap();
|
let result = decimal_add(a.to_string(), b.to_string()).unwrap();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
@@ -255,26 +255,21 @@ fn test_precision_preservation(#[case] a: &str, #[case] b: &str, #[case] expecte
|
|||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test explicit precision functions
|
// Test explicit precision using global precision setting
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case("5.123", "2.456", 0, "8")] // 0 decimal places
|
#[case("5.123", "2.456", 0, "8")] // 0 decimal places
|
||||||
#[case("5.123", "2.456", 2, "7.58")] // 2 decimal places
|
#[case("5.123", "2.456", 2, "7.58")] // 2 decimal places
|
||||||
#[case("5.123", "2.456", 4, "7.5790")] // 4 decimal places
|
#[case("5.12312", "2.45622", 4, "7.5793")] // 4 decimal places
|
||||||
fn test_explicit_precision(#[case] a: &str, #[case] b: &str, #[case] precision: u32, #[case] expected: &str) {
|
fn test_explicit_precision(#[case] a: &str, #[case] b: &str, #[case] precision: u32, #[case] expected: &str) {
|
||||||
let result = decimal_add_p(a.to_string(), b.to_string(), precision).unwrap();
|
// Set precision globally
|
||||||
assert_eq!(result, expected);
|
set_precision(precision);
|
||||||
}
|
|
||||||
|
|
||||||
// Test scientific notation edge cases
|
// Test with precision set
|
||||||
#[rstest]
|
let result = decimal_add(a.to_string(), b.to_string()).unwrap();
|
||||||
#[case("1e0", "1")] // Simple case
|
|
||||||
#[case("1.0e0", "1.0")] // Preserves decimal
|
|
||||||
#[case("1e-2", "0.01")] // Negative exponent
|
|
||||||
#[case("1.5e-3", "0.0015")] // Decimal + negative exponent
|
|
||||||
#[case("2.5e2", "250.0")] // Decimal + positive exponent
|
|
||||||
fn test_scientific_edge_cases(#[case] input: &str, #[case] expected: &str) {
|
|
||||||
let result = to_decimal(input.to_string()).unwrap();
|
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
|
|
||||||
|
// Clean up - clear precision for other tests
|
||||||
|
clear_precision();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test precision functions
|
// Test precision functions
|
||||||
@@ -289,9 +284,58 @@ fn test_precision_functions() {
|
|||||||
assert_eq!(result, "4.46");
|
assert_eq!(result, "4.46");
|
||||||
|
|
||||||
// Test clearing precision
|
// Test clearing precision
|
||||||
|
assert_eq!(clear_precision(), "Precision cleared - using full precision");
|
||||||
assert_eq!(get_precision(), "full");
|
assert_eq!(get_precision(), "full");
|
||||||
|
|
||||||
// Test with full precision
|
// Test with full precision
|
||||||
let result = decimal_add("1.567".to_string(), "2.891".to_string()).unwrap();
|
let result = decimal_add("1.567".to_string(), "2.891".to_string()).unwrap();
|
||||||
assert_eq!(result, "4.458");
|
assert_eq!(result, "4.458");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test decimal_format function
|
||||||
|
#[rstest]
|
||||||
|
#[case("5.123456", 2, "5.12")]
|
||||||
|
#[case("5.123456", 4, "5.1235")]
|
||||||
|
#[case("5.999", 0, "6")]
|
||||||
|
fn test_decimal_format(#[case] value: &str, #[case] precision: u32, #[case] expected: &str) {
|
||||||
|
let result = decimal_format(value.to_string(), precision).unwrap();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test precision doesn't affect comparison functions
|
||||||
|
#[test]
|
||||||
|
fn test_precision_does_not_affect_comparisons() {
|
||||||
|
set_precision(2);
|
||||||
|
|
||||||
|
// Comparisons should use full precision internally
|
||||||
|
assert_eq!(decimal_gt("1.567".to_string(), "1.566".to_string()).unwrap(), true);
|
||||||
|
assert_eq!(decimal_eq("1.567".to_string(), "1.567".to_string()).unwrap(), true);
|
||||||
|
assert_eq!(decimal_eq("1.567".to_string(), "1.57".to_string()).unwrap(), false);
|
||||||
|
|
||||||
|
clear_precision();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test precision edge cases
|
||||||
|
#[test]
|
||||||
|
fn test_precision_edge_cases() {
|
||||||
|
// Test max precision
|
||||||
|
assert_eq!(set_precision(28), "Precision set to 28 decimal places");
|
||||||
|
|
||||||
|
// Test beyond max precision
|
||||||
|
assert_eq!(set_precision(29), "Error: Maximum precision is 28 decimal places");
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
clear_precision();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test scientific notation edge cases
|
||||||
|
#[rstest]
|
||||||
|
#[case("1e0", "1")] // Simple case
|
||||||
|
#[case("1.0e0", "1.0")] // Preserves decimal
|
||||||
|
#[case("1e-2", "0.01")] // Negative exponent
|
||||||
|
#[case("1.5e-3", "0.0015")] // Decimal + negative exponent
|
||||||
|
#[case("2.5e2", "250.0")] // Decimal + positive exponent
|
||||||
|
fn test_scientific_edge_cases(#[case] input: &str, #[case] expected: &str) {
|
||||||
|
let result = to_decimal(input.to_string()).unwrap();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ fn test_financial_calculations() {
|
|||||||
let result = steel_decimal_instance.parse_and_execute("(decimal-compound \"1000\" \"0.05\" \"2\")").unwrap();
|
let result = steel_decimal_instance.parse_and_execute("(decimal-compound \"1000\" \"0.05\" \"2\")").unwrap();
|
||||||
assert_eq!(result.len(), 1);
|
assert_eq!(result.len(), 1);
|
||||||
if let SteelVal::StringV(s) = &result[0] {
|
if let SteelVal::StringV(s) = &result[0] {
|
||||||
assert_eq!(s.to_string(), "1102.50"); // 1000 * (1.05)^2 = 1102.50
|
assert_eq!(s.to_string(), "1102.5000"); // 1000 * (1.05)^2 = 1102.5000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user