From d686a64266e2547162e50577697b7f8779d6eeb6 Mon Sep 17 00:00:00 2001 From: Raushan Prabhakar Date: Sun, 17 May 2026 00:15:04 +0530 Subject: [PATCH] fixing negative power to zero --- datafusion/functions/src/math/power.rs | 30 ++++++++++++++++++--- datafusion/sqllogictest/test_files/math.slt | 10 ++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/datafusion/functions/src/math/power.rs b/datafusion/functions/src/math/power.rs index ea7c85a33782e..ae48521d95bb3 100644 --- a/datafusion/functions/src/math/power.rs +++ b/datafusion/functions/src/math/power.rs @@ -38,6 +38,17 @@ use datafusion_expr::{ use datafusion_macros::user_doc; use num_traits::{NumCast, ToPrimitive}; +/// Matches PostgreSQL: `power(0::float8, negative)` is undefined (IEEE 754 would yield infinity). +#[inline] +fn float64_power_checked(base: f64, exp: f64) -> Result { + if base == 0.0 && exp < 0.0 { + return Err(ArrowError::ComputeError( + "zero raised to a negative power is undefined".to_string(), + )); + } + Ok(base.powf(exp)) +} + #[user_doc( doc_section(label = "Math Functions"), description = "Returns a base expression raised to the power of an exponent.", @@ -203,7 +214,7 @@ fn compute_pow_f64_result( scale: i8, exp: f64, ) -> Result { - let result_f64 = base_f64.powf(exp); + let result_f64 = float64_power_checked(base_f64, exp)?; if !result_f64.is_finite() { return Err(ArrowError::ArithmeticOverflow(format!( @@ -382,7 +393,7 @@ fn pow_decimal_with_float_fallback( let result_f64 = calculate_binary_math::( &base_f64, &ColumnarValue::Array(exp_f64), - |b, e| Ok(f64::powf(b, e)), + float64_power_checked, )?; let result = cast(result_f64.as_ref(), &original_type)?; @@ -436,7 +447,7 @@ impl ScalarUDFImpl for PowerFunc { calculate_binary_math::( &base, exponent, - |b, e| Ok(f64::powf(b, e)), + float64_power_checked, )? } (DataType::Decimal32(precision, scale), DataType::Int64) => { @@ -657,5 +668,18 @@ mod tests { // Test non-finite exponent returns error assert!(pow_decimal_float(100i128, 2, f64::NAN).is_err()); assert!(pow_decimal_float(100i128, 2, f64::INFINITY).is_err()); + + // PostgreSQL: zero to a negative power is undefined + assert!(pow_decimal_float(0i128, 2, -1.0).is_err()); + } + + #[test] + fn test_float64_power_checked_zero_negative_exp() { + assert_eq!(float64_power_checked(0.0, 1.0).unwrap(), 0.0); + assert_eq!(float64_power_checked(2.0, -1.0).unwrap(), 0.5); + for base in [0.0f64, -0.0] { + assert!(float64_power_checked(base, -1.0).is_err()); + assert!(float64_power_checked(base, -0.5).is_err()); + } } } diff --git a/datafusion/sqllogictest/test_files/math.slt b/datafusion/sqllogictest/test_files/math.slt index e00edf47c176b..9e55f5cb89e39 100644 --- a/datafusion/sqllogictest/test_files/math.slt +++ b/datafusion/sqllogictest/test_files/math.slt @@ -742,11 +742,13 @@ SELECT pow(-2, -0.5) ---- NaN -# pow() with zero base and negative exponent (returns Infinity) -query R +# pow() with zero base and negative exponent (PostgreSQL: domain error) +query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined SELECT pow(0, -0.5) ----- -Infinity + +# power(0::float8, negative::float8) - issue #22272 +query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined +SELECT power(0.0::float8, -1.0::float8) # pow() with integer base of 1 and negative exponent query R