Yuvraj-cyborg commented on code in PR #19369:
URL: https://github.com/apache/datafusion/pull/19369#discussion_r2633983006


##########
datafusion/functions/src/math/power.rs:
##########
@@ -149,22 +151,118 @@ where
 
 /// Binary function to calculate a math power to float exponent
 /// for scaled integer types.
-/// Returns error if exponent is negative or non-integer, or base invalid
 fn pow_decimal_float<T>(base: T, scale: i8, exp: f64) -> Result<T, ArrowError>
 where
     T: From<i32> + ArrowNativeTypeOp,
 {
-    if !exp.is_finite() || exp.trunc() != exp {
+    if exp.is_finite() && exp.trunc() == exp && exp >= 0f64 && exp < u32::MAX 
as f64 {
+        return pow_decimal_int(base, scale, exp as i64);
+    }
+
+    if !exp.is_finite() {
         return Err(ArrowError::ComputeError(format!(
-            "Cannot use non-integer exp: {exp}"
+            "Cannot use non-finite exp: {exp}"
+        )));
+    }
+
+    pow_decimal_float_fallback(base, scale, exp)
+}
+
+/// Fallback implementation using f64 for negative or non-integer exponents.
+/// This handles cases that cannot be computed using integer arithmetic.
+fn pow_decimal_float_fallback<T>(base: T, scale: i8, exp: f64) -> Result<T, 
ArrowError>
+where
+    T: From<i32> + ArrowNativeTypeOp,
+{
+    if scale < 0 {
+        return Err(ArrowError::NotYetImplemented(format!(
+            "Negative scale is not yet supported: {scale}"
+        )));
+    }
+
+    let scale_factor = 10f64.powi(scale as i32);
+    let base_f64 = format!("{base:?}")
+        .parse::<f64>()
+        .map(|v| v / scale_factor)
+        .map_err(|_| {
+            ArrowError::ComputeError(format!("Cannot convert base {base:?} to 
f64"))
+        })?;
+
+    let result_f64 = base_f64.powf(exp);
+
+    if !result_f64.is_finite() {
+        return Err(ArrowError::ArithmeticOverflow(format!(
+            "Result of {base_f64}^{exp} is not finite"
         )));
     }
-    if exp < 0f64 || exp >= u32::MAX as f64 {
+
+    let result_scaled = result_f64 * scale_factor;
+    let result_rounded = result_scaled.round();
+
+    if result_rounded.abs() > i128::MAX as f64 {
         return Err(ArrowError::ArithmeticOverflow(format!(
-            "Unsupported exp value: {exp}"
+            "Result {result_rounded} is too large for the target decimal type"
         )));
     }
-    pow_decimal_int(base, scale, exp as i64)
+
+    decimal_from_i128::<T>(result_rounded as i128)
+}
+
+fn decimal_from_i128<T>(value: i128) -> Result<T, ArrowError>
+where
+    T: From<i32> + ArrowNativeTypeOp,
+{
+    if value == 0 {
+        return Ok(T::from(0));
+    }
+
+    if value >= i32::MIN as i128 && value <= i32::MAX as i128 {
+        return Ok(T::from(value as i32));
+    }
+
+    let is_negative = value < 0;
+    let abs_value = value.unsigned_abs();
+
+    let billion = 1_000_000_000u128;
+    let mut result = T::from(0);
+    let mut multiplier = T::from(1);
+    let billion_t = T::from(1_000_000_000);
+
+    let mut remaining = abs_value;
+    while remaining > 0 {
+        let chunk = (remaining % billion) as i32;
+        remaining /= billion;
+
+        let chunk_value = T::from(chunk).mul_checked(multiplier).map_err(|_| {
+            ArrowError::ArithmeticOverflow(format!(
+                "Overflow while converting {value} to decimal type"
+            ))
+        })?;
+

Review Comment:
   converting an i128 result back to the generic type T (which could be i32, 
i64, i128, or i256). Since we can't directly convert i128 → T for all types, so 
we split the i128 into chunks of 10^9 (a billion), which fits in i32. Then we 
reconstruct T by: chunk[n] * (10^9)^n + chunk[n-1] * (10^9)^(n-1) + and so on.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to