Rafferty97 commented on code in PR #9453:
URL: https://github.com/apache/arrow-rs/pull/9453#discussion_r2927926500
##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -614,6 +615,62 @@ impl i256 {
let n = (n.high >> 64) as i64; // throw away the lower 192 bits
(n as f64) * f64::powi(2.0, 192 - (k as i32)) // convert to f64 and
scale it, as we left-shift k bit previous, so we need to scale it by 2^(192-k)
}
+
+ /// Computes the `base` logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero, or if `base`
is less than 2.
+ #[inline]
+ pub fn checked_ilog(self, base: i256) -> Option<u32> {
+ if self <= Self::ZERO || base < i256::from(2) {
+ None
+ } else {
+ // Invariants are enforced, so this call cannot fail
+ self.to_ext_i256().checked_ilog(base.to_ext_i256())
+ }
+ }
+
+ /// Computes the `base` logarithm of the number `self`
+ /// Panic if `self` is less than or equal to zero, or if `base` is less
than 2.
+ #[inline]
+ pub fn ilog(self, base: i256) -> u32 {
+ self.checked_ilog(base)
+ .unwrap_or_else(|| panic!("ilog overflow with {self} and base
{base}"))
+ }
+
+ /// Computes the decimal logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero.
+ #[inline]
+ pub fn checked_ilog10(self) -> Option<u32> {
+ // Switch to I256::checked_ilog10 when I256 switches MSRV
Review Comment:
Why can't it be used now?
##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -614,6 +615,62 @@ impl i256 {
let n = (n.high >> 64) as i64; // throw away the lower 192 bits
(n as f64) * f64::powi(2.0, 192 - (k as i32)) // convert to f64 and
scale it, as we left-shift k bit previous, so we need to scale it by 2^(192-k)
}
+
+ /// Computes the `base` logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero, or if `base`
is less than 2.
+ #[inline]
+ pub fn checked_ilog(self, base: i256) -> Option<u32> {
+ if self <= Self::ZERO || base < i256::from(2) {
Review Comment:
Since these invariants are checked by the call to `ExtI256::checked_ilog`
anyway, what's the point of restating the logic here? The `to_ext_i256` calls
should be no-ops anyway.
##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -1580,4 +1637,69 @@ mod tests {
assert_eq!(i256::MAX.trailing_zeros(), 0);
assert_eq!(i256::from(-1).trailing_zeros(), 0);
}
+
+ #[test]
+ fn test_ilog() {
+ let value = i256::from(128);
+
+ // log2
+ assert_eq!(value.ilog(i256::from(2)), 7);
+ assert_eq!(value.ilog2(), 7);
+
+ // log10
+ assert_eq!(value.ilog(i256::from(10)), 2);
+ assert_eq!(value.ilog10(), 2);
+
+ // negative base
+ assert_eq!(value.checked_ilog(i256::from(-2)), None);
+ assert_eq!(value.checked_ilog(i256::from(-10)), None);
+ assert_eq!(value.checked_ilog(i256::from(0)), None);
+ assert_eq!(value.checked_ilog(i256::from(1)), None);
+
+ // negative self
+ let neg_value = i256::from(-128);
+ assert_eq!(neg_value.checked_ilog(i256::from(2)), None);
+ assert_eq!(neg_value.checked_ilog(i256::from(10)), None);
+ assert_eq!(neg_value.checked_ilog10(), None);
+ assert_eq!(neg_value.checked_ilog2(), None);
+
+ // zero self
+ assert_eq!(i256::ZERO.checked_ilog(i256::from(2)), None);
+ assert_eq!(i256::ZERO.checked_ilog(i256::from(10)), None);
+ assert_eq!(i256::ZERO.checked_ilog10(), None);
+ assert_eq!(i256::ZERO.checked_ilog2(), None);
+
+ // Large i256 values
+ let large = i256::from_parts(100000000, i128::MAX);
+ // log2 of 2 powered to approximately 255 should be 254
+ assert_eq!(large.checked_ilog(i256::from(2)), Some(254));
+
+ // log10 should be 76 or 77
+ let result = large.checked_ilog(i256::from(10));
+ assert!(result.is_some());
+ assert!(result.unwrap() >= 76 && result.unwrap() <= 77);
Review Comment:
Why can't an `assert_eq!` be used here? Surely the result is deterministic?
##########
arrow-buffer/src/bigint/mod.rs:
##########
@@ -614,6 +615,62 @@ impl i256 {
let n = (n.high >> 64) as i64; // throw away the lower 192 bits
(n as f64) * f64::powi(2.0, 192 - (k as i32)) // convert to f64 and
scale it, as we left-shift k bit previous, so we need to scale it by 2^(192-k)
}
+
+ /// Computes the `base` logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero, or if `base`
is less than 2.
+ #[inline]
+ pub fn checked_ilog(self, base: i256) -> Option<u32> {
+ if self <= Self::ZERO || base < i256::from(2) {
+ None
+ } else {
+ // Invariants are enforced, so this call cannot fail
+ self.to_ext_i256().checked_ilog(base.to_ext_i256())
+ }
+ }
+
+ /// Computes the `base` logarithm of the number `self`
+ /// Panic if `self` is less than or equal to zero, or if `base` is less
than 2.
+ #[inline]
+ pub fn ilog(self, base: i256) -> u32 {
+ self.checked_ilog(base)
+ .unwrap_or_else(|| panic!("ilog overflow with {self} and base
{base}"))
+ }
+
+ /// Computes the decimal logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero.
+ #[inline]
+ pub fn checked_ilog10(self) -> Option<u32> {
+ // Switch to I256::checked_ilog10 when I256 switches MSRV
+ self.checked_ilog(i256::from(10))
+ }
+
+ /// Computes the decimal logarithm of the number `self`
+ /// Panics if `self` is less than or equal to zero.
+ #[inline]
+ pub fn ilog10(self) -> u32 {
+ self.checked_ilog10()
+ .unwrap_or_else(|| panic!("ilog10 overflow with {self}"))
+ }
+
+ /// Computes the binary logarithm of the number `self`
+ /// Returns `None` if `self` is less than or equal to zero.
+ #[inline]
+ pub fn checked_ilog2(self) -> Option<u32> {
+ // Switch to I256::checked_ilog2 when I256 switches MSRV
Review Comment:
Same as above: why not now?
--
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]