You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by vi...@apache.org on 2022/10/27 21:46:08 UTC

[arrow-rs] branch master updated: Add pow to i256 (#2955)

This is an automated email from the ASF dual-hosted git repository.

viirya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new 63417b1f3 Add pow to i256 (#2955)
63417b1f3 is described below

commit 63417b1f36461d4abf7c0aedc6f49e740a92e687
Author: Liang-Chi Hsieh <vi...@gmail.com>
AuthorDate: Thu Oct 27 14:46:02 2022 -0700

    Add pow to i256 (#2955)
---
 arrow-buffer/src/bigint.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/arrow-buffer/src/bigint.rs b/arrow-buffer/src/bigint.rs
index 3518b85e4..fe135b329 100644
--- a/arrow-buffer/src/bigint.rs
+++ b/arrow-buffer/src/bigint.rs
@@ -305,6 +305,55 @@ impl i256 {
         let (val, overflow) = Self::from_bigint_with_overflow(l % r);
         (!overflow).then_some(val)
     }
+
+    /// Performs checked exponentiation
+    #[inline]
+    pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
+        if exp == 0 {
+            return Some(i256::from_i128(1));
+        }
+
+        let mut base = self;
+        let mut acc: Self = i256::from_i128(1);
+
+        while exp > 1 {
+            if (exp & 1) == 1 {
+                acc = acc.checked_mul(base)?;
+            }
+            exp /= 2;
+            base = base.checked_mul(base)?;
+        }
+        // since exp!=0, finally the exp must be 1.
+        // Deal with the final bit of the exponent separately, since
+        // squaring the base afterwards is not necessary and may cause a
+        // needless overflow.
+        acc.checked_mul(base)
+    }
+
+    /// Performs wrapping exponentiation
+    #[inline]
+    pub fn wrapping_pow(self, mut exp: u32) -> Self {
+        if exp == 0 {
+            return i256::from_i128(1);
+        }
+
+        let mut base = self;
+        let mut acc: Self = i256::from_i128(1);
+
+        while exp > 1 {
+            if (exp & 1) == 1 {
+                acc = acc.wrapping_mul(base);
+            }
+            exp /= 2;
+            base = base.wrapping_mul(base);
+        }
+
+        // since exp!=0, finally the exp must be 1.
+        // Deal with the final bit of the exponent separately, since
+        // squaring the base afterwards is not necessary and may cause a
+        // needless overflow.
+        acc.wrapping_mul(base)
+    }
 }
 
 /// Performs an unsigned multiplication of `a * b` returning a tuple of
@@ -455,6 +504,39 @@ mod tests {
                 expected
             ),
         }
+
+        // Exponentiation
+        for exp in vec![0, 1, 3, 8, 100].into_iter() {
+            let actual = il.wrapping_pow(exp);
+            let (expected, overflow) =
+                i256::from_bigint_with_overflow(bl.clone().pow(exp));
+            assert_eq!(actual.to_string(), expected.to_string());
+
+            let checked = il.checked_pow(exp);
+            match overflow {
+                true => assert!(
+                    checked.is_none(),
+                    "{} ^ {} = {} vs {} * {} = {}",
+                    il,
+                    exp,
+                    actual,
+                    bl,
+                    exp,
+                    expected
+                ),
+                false => assert_eq!(
+                    checked.unwrap(),
+                    actual,
+                    "{} ^ {} = {} vs {} * {} = {}",
+                    il,
+                    exp,
+                    actual,
+                    bl,
+                    exp,
+                    expected
+                ),
+            }
+        }
     }
 
     #[test]