diff --git a/base/src/cast.rs b/base/src/cast.rs index 912594d..33fe7af 100644 --- a/base/src/cast.rs +++ b/base/src/cast.rs @@ -15,6 +15,23 @@ pub(crate) enum NumberOrArray { } impl Model { + pub(crate) fn cast_number(&self, s: &str) -> Option { + match s.trim().parse::() { + Ok(f) => Some(f), + _ => { + let currency = &self.locale.currency.symbol; + let mut currencies = vec!["$", "€"]; + if !currencies.iter().any(|e| *e == currency) { + currencies.push(currency); + } + // Try to parse as a formatted number (e.g., dates, currencies, percentages) + if let Ok((v, _number_format)) = parse_formatted_number(s, ¤cies) { + return Some(v); + } + None + } + } + } pub(crate) fn get_number_or_array( &mut self, node: &Node, @@ -22,24 +39,13 @@ impl Model { ) -> Result { match self.evaluate_node_in_context(node, cell) { CalcResult::Number(f) => Ok(NumberOrArray::Number(f)), - CalcResult::String(s) => match s.parse::() { - Ok(f) => Ok(NumberOrArray::Number(f)), - _ => { - let mut currencies = vec!["$", "€"]; - let currency = &self.locale.currency.symbol; - if !currencies.iter().any(|e| e == currency) { - currencies.push(currency); - } - // Try to parse as a formatted number (e.g., dates, currencies, percentages) - if let Ok((v, _number_format)) = parse_formatted_number(&s, ¤cies) { - return Ok(NumberOrArray::Number(v)); - } - Err(CalcResult::new_error( - Error::VALUE, - cell, - "Expecting number".to_string(), - )) - } + CalcResult::String(s) => match self.cast_number(&s) { + Some(f) => Ok(NumberOrArray::Number(f)), + None => Err(CalcResult::new_error( + Error::VALUE, + cell, + "Expecting number".to_string(), + )), }, CalcResult::Boolean(f) => { if f { @@ -108,24 +114,13 @@ impl Model { ) -> Result { match result { CalcResult::Number(f) => Ok(f), - CalcResult::String(s) => match s.trim().parse::() { - Ok(f) => Ok(f), - _ => { - let mut currencies = vec!["$", "€"]; - let currency = &self.locale.currency.symbol; - if !currencies.iter().any(|e| e == currency) { - currencies.push(currency); - } - // Try to parse as a formatted number (e.g., dates, currencies, percentages) - if let Ok((v, _number_format)) = parse_formatted_number(&s, ¤cies) { - return Ok(v); - } - Err(CalcResult::new_error( - Error::VALUE, - cell, - "Expecting number".to_string(), - )) - } + CalcResult::String(s) => match self.cast_number(&s) { + Some(f) => Ok(f), + None => Err(CalcResult::new_error( + Error::VALUE, + cell, + "Expecting number".to_string(), + )), }, CalcResult::Boolean(f) => { if f { diff --git a/base/src/functions/macros.rs b/base/src/functions/macros.rs index 378aa18..336954f 100644 --- a/base/src/functions/macros.rs +++ b/base/src/functions/macros.rs @@ -68,14 +68,14 @@ macro_rules! single_number_fn { }, // If String, parse to f64 then apply or #VALUE! error ArrayNode::String(s) => { - let node = match s.parse::() { - Ok(f) => match $op(f) { + let node = match self.cast_number(&s) { + Some(f) => match $op(f) { Ok(x) => ArrayNode::Number(x), Err(Error::DIV) => ArrayNode::Error(Error::DIV), Err(Error::VALUE) => ArrayNode::Error(Error::VALUE), Err(e) => ArrayNode::Error(e), }, - Err(_) => ArrayNode::Error(Error::VALUE), + None => ArrayNode::Error(Error::VALUE), }; data_row.push(node); } diff --git a/base/src/functions/mathematical.rs b/base/src/functions/mathematical.rs index 057fff6..025e109 100644 --- a/base/src/functions/mathematical.rs +++ b/base/src/functions/mathematical.rs @@ -1336,7 +1336,13 @@ impl Model { } Ok(acc) }); - single_number_fn!(fn_sign, |f| Ok(f64::signum(f))); + single_number_fn!(fn_sign, |f| { + if f == 0.0 { + Ok(0.0) + } else { + Ok(f64::signum(f)) + } + }); single_number_fn!(fn_degrees, |f| Ok(f * (180.0 / PI))); single_number_fn!(fn_radians, |f| Ok(f * (PI / 180.0))); single_number_fn!(fn_odd, |f| { diff --git a/xlsx/tests/calc_tests/EXP_SIGN.xlsx b/xlsx/tests/calc_tests/EXP_SIGN.xlsx new file mode 100644 index 0000000..6774bdd Binary files /dev/null and b/xlsx/tests/calc_tests/EXP_SIGN.xlsx differ