Jefffrey commented on code in PR #22306:
URL: https://github.com/apache/datafusion/pull/22306#discussion_r3325257896


##########
datafusion/functions/src/math/factorial.rs:
##########
@@ -139,14 +155,27 @@ const FACTORIALS: [i64; 21] = [
     6402373705728000,
     121645100408832000,
     2432902008176640000,
-]; // if return type changes, this constant needs to be updated accordingly
+];
 
-fn compute_factorial(n: i64) -> Result<i64> {
+fn compute_factorial(n: i64) -> Result<i256> {
     if n < 0 {
-        exec_err!("factorial of a negative number is undefined")
-    } else if n < FACTORIALS.len() as i64 {
-        Ok(FACTORIALS[n as usize])
-    } else {
-        exec_err!("Overflow happened on FACTORIAL({n})")
+        return exec_err!("factorial of a negative number is undefined");
+    }
+
+    if n < FACTORIALS.len() as i64 {
+        return Ok(i256::from(FACTORIALS[n as usize]));
+    }
+
+    let mut result = i256::from(FACTORIALS[FACTORIALS.len() - 1]);
+    for value in FACTORIALS.len() as i64..=n {
+        result = result.checked_mul(i256::from(value)).ok_or_else(|| {
+            DataFusionError::Execution(format!("Overflow happened on 
FACTORIAL({n})"))
+        })?;
+    }
+
+    if result.to_string().len() > DECIMAL256_MAX_PRECISION as usize {

Review Comment:
   we could consider extending the lookup table to 56 entries which removes the 
need for the multiplication & validation path



##########
datafusion/functions/src/math/factorial.rs:
##########
@@ -100,9 +112,13 @@ impl ScalarUDFImpl for FactorialFunc {
             }
             ColumnarValue::Array(array) => match array.data_type() {
                 Int64 => {
-                    let result: Int64Array = array
+                    let result = array

Review Comment:
   we can keep the try_unary which should be much simpler, e.g.
   
   ```rust
                       let result = array
                           .as_primitive::<Int64Type>()
                           .try_unary::<_, Decimal256Type, 
_>(compute_factorial)?
                           .with_precision_and_scale(DECIMAL256_MAX_PRECISION, 
0)?;
                       Ok(ColumnarValue::Array(Arc::new(result) as ArrayRef))
   ```



-- 
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