andygrove commented on code in PR #11425:
URL: https://github.com/apache/arrow-rs/pull/11425#discussion_r4212165219


##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -572,6 +572,48 @@ impl i256 {
         self.div_rem(other).map(|(_, v)| v).ok()
     }
 
+    /// Performs wrapping division and remainder, returning `(quotient, 
remainder)`
+    ///
+    /// # Panics
+    ///
+    /// Panics if `other` is zero
+    ///
+    /// # Example
+    /// ```
+    /// # use arrow_buffer::i256;
+    /// let (q, r) = i256::from_i128(-7).wrapping_div_rem(i256::from_i128(2));
+    /// assert_eq!((q, r), (i256::from_i128(-3), i256::from_i128(-1)));
+    ///
+    /// let (q, r) = i256::MIN.wrapping_div_rem(i256::MINUS_ONE);
+    /// assert_eq!((q, r), (i256::MIN, i256::ZERO));
+    /// ```
+    #[inline]
+    pub fn wrapping_div_rem(self, other: Self) -> (Self, Self) {
+        match self.div_rem(other) {
+            Ok(v) => v,
+            Err(DivRemError::DivideByZero) => panic!("attempt to divide by 
zero"),
+            Err(_) => (Self::MIN, Self::ZERO),
+        }
+    }

Review Comment:
   This is now the third copy of the zero-divisor panic and the `MIN / -1` 
fallback, after `wrapping_div` and `wrapping_rem` above. Those two could become 
`self.wrapping_div_rem(other).0` and `.1`, which keeps the error handling in 
one place and lets `test_wrapping_div_rem_zero_panics` cover the panic for all 
three. All three are `#[inline]` and `div_rem` always computes both values, so 
it costs nothing at runtime.
   
   Matching `Err(DivRemError::DivideOverflow)` instead of `Err(_)` would also 
turn a future `DivRemError` variant into a compile error here instead of a 
silent `(MIN, 0)`.
   



##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -572,6 +572,48 @@ impl i256 {
         self.div_rem(other).map(|(_, v)| v).ok()
     }
 
+    /// Performs wrapping division and remainder, returning `(quotient, 
remainder)`

Review Comment:
   The first commit had a sentence saying this does one division where calling 
`wrapping_div` and `wrapping_rem` does two. I'd keep it, since it's the main 
reason to call these methods. It would also help to say in words what the 
examples show: the quotient truncates toward zero, the remainder has the sign 
of the dividend, and `MIN / -1` returns `(MIN, 0)` (or `None` from 
`checked_div_rem`). A pointer from the `wrapping_div`/`wrapping_rem` docs would 
help people find these methods.
   



##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -1621,6 +1671,71 @@ mod tests {
         }
     }
 
+    fn test_div_rem(n: i256, d: i256) {
+        let bn = BigInt::from_signed_bytes_le(&n.to_le_bytes());
+        let bd = BigInt::from_signed_bytes_le(&d.to_le_bytes());
+
+        // BigInt produces an integer over i256::MAX for i256::MIN / -1
+        let (q, overflow) = i256::from_bigint_with_overflow(bn.clone() / 
bd.clone());
+        let (r, _) = i256::from_bigint_with_overflow(bn % bd);
+
+        assert_eq!(n.wrapping_div_rem(d), (q, r), "{n} / {d}");
+        assert_eq!(
+            n.checked_div_rem(d),
+            (!overflow).then_some((q, r)),
+            "{n} / {d}"
+        );
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Takes too long
+    fn test_div_rem_powers_of_ten() {
+        let dividends = [
+            i256::ZERO,
+            i256::ONE,
+            i256::MIN,
+            i256::MIN + i256::ONE,

Review Comment:
   nit: `i256::MIN + i256::ONE` is `-i256::MAX`, so with the four sign 
combinations below it produces exactly the same `(n, d)` pairs as `i256::MAX` 
and could be dropped.
   



##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -1621,6 +1671,71 @@ mod tests {
         }
     }
 
+    fn test_div_rem(n: i256, d: i256) {

Review Comment:
   nit: this recomputes the `BigInt` reference values that the Division and 
Remainder sections of `test_ops` already compute, and checks the `MIN / -1` 
case a second way (the overflow flag here, the explicit `ir == i256::MINUS_ONE 
&& il == i256::MIN` check there). If this helper also asserted `wrapping_div`, 
`wrapping_rem`, `checked_div` and `checked_rem`, those sections could become a 
single `test_div_rem(il, ir)` call, and `test_div_rem_powers_of_ten` would 
cover the single-op methods as well.
   
   It could also handle `d == 0` itself, asserting that `checked_div_rem` 
returns `None` and returning before the `BigInt` division panics. That would 
replace both the if/else in `test_ops` and the `continue` in 
`test_div_rem_powers_of_ten`.
   



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

Reply via email to