You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/05/19 20:48:02 UTC
(datafusion) 01/01: fixing negative power to zero (#22277)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-22277-fd81bfbfcf924bf34f80d70ac213a733ec793eb2
in repository https://gitbox.apache.org/repos/asf/datafusion.git
commit 641f53a24c9d85db6c1375edbb0393e07eb4ae4c
Author: Raushan Prabhakar <48...@users.noreply.github.com>
AuthorDate: Wed May 20 01:35:17 2026 +0530
fixing negative power to zero (#22277)
## Which issue does this PR close?
- Closes #22272
## Rationale for this change
PostgreSQL rejects `power(0::float8, negative::float8)` because zero
raised to a negative power is undefined. DataFusion used `f64::powf`,
which returns infinity for that case. This aligns float (and related
decimal float paths) with PostgreSQL’s domain semantics.
## What changes are included in this PR?
- Added `float64_power_checked` to error when `base == 0.0` and `exp <
0.0` with message `zero raised to a negative power is undefined`.
- Wired it into `Float64`/`Float64` `power`, decimal array-exponent
float fallback, and `compute_pow_f64_result`.
- Updated `math.slt` expectations for `pow(0, -0.5)` and added coverage
for `power(0.0::float8, -1.0::float8)`.
- Added unit tests in `power.rs`.
## Are these changes tested?
Yes. Unit tests in `datafusion/functions/src/math/power.rs`, and SQL
logic tests in `datafusion/sqllogictest/test_files/math.slt` (including
the regression for #22272).
## Are there any user-facing changes?
Yes. Queries that previously returned positive infinity for `power` /
`pow` with a zero base and negative exponent now return a runtime error
(compute error) with that message, matching PostgreSQL for this case.
No public Rust API signature changes; treat as SQL/runtime behavior only
unless your process labels SQL semantics as API.
---------
Co-authored-by: Raushan Prabhakar <ro...@Raushans-MacBook-Air.local>
---
datafusion/functions/src/math/power.rs | 37 ++++++++++++++++++++++++++---
datafusion/sqllogictest/test_files/math.slt | 26 ++++++++++++++++----
2 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/datafusion/functions/src/math/power.rs b/datafusion/functions/src/math/power.rs
index ea7c85a337..3fe30a1ffa 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<f64, ArrowError> {
+ 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<i128, ArrowError> {
- 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::<Float64Type, Float64Type, Float64Type, _>(
&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::<Float64Type, Float64Type, Float64Type, _>(
&base,
exponent,
- |b, e| Ok(f64::powf(b, e)),
+ float64_power_checked,
)?
}
(DataType::Decimal32(precision, scale), DataType::Int64) => {
@@ -657,5 +668,25 @@ 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_pow_decimal256_zero_to_negative_exp_errors() {
+ assert!(pow_decimal256_float(i256::ZERO, 2, -1.0).is_err());
+ // Negative integer exponent uses pow_decimal256_float via pow_decimal256_int
+ assert!(pow_decimal256_int(i256::ZERO, 2, -1).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 8f7245365f..475434883d 100644
--- a/datafusion/sqllogictest/test_files/math.slt
+++ b/datafusion/sqllogictest/test_files/math.slt
@@ -742,11 +742,29 @@ 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)
+
+# zero base, negative exponent: exact Decimal+Int64 path (pow_decimal_int → pow_decimal_float)
+query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined
+SELECT pow(0::decimal(38, 0), -2::bigint)
+
+# bigint operands (typically coerced to float); still must reject 0^(negative)
+query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined
+SELECT pow(0::bigint, -2::bigint)
+
+# decimal base + float scalar exponent (compute_pow_f64_result / pow_decimal_float fallback)
+query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined
+SELECT pow(0.0::decimal(10,2), -1.0)
+
+# decimal base + array exponent (pow_decimal_with_float_fallback)
+query error DataFusion error: Arrow error: Compute error: zero raised to a negative power is undefined
+SELECT power(base, exp) FROM (VALUES (0.0::decimal(10,2), -1.0::float8)) AS t(base, exp)
# pow() with integer base of 1 and negative exponent
query R
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org