Skip to content

Commit

Permalink
Use the recently stabilized checked_ilog
Browse files Browse the repository at this point in the history
  • Loading branch information
Dentosal committed Jan 27, 2023
1 parent 16403f2 commit c32292b
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 48 deletions.
45 changes: 1 addition & 44 deletions fuel-vm/src/interpreter/executors/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ where
self.gas_charge(self.gas_costs.mlog)?;
self.alu_error(
ra,
|b, c| checked_ilog(b, c).expect("checked_ilog returned None for valid values") as Word,
|b, c| b.checked_ilog(c).expect("checked_ilog returned None for valid values") as Word,
b,
c,
b == 0 || c <= 1,
Expand Down Expand Up @@ -546,48 +546,5 @@ fn checked_nth_root(target: u64, nth_root: u64) -> Option<u64> {
Some(guess + 1)
}

/// Computes logarithm for given exponent and base.
/// Diverges when exp == 0 or base <= 1.
///
/// This code is originally from [rust corelib][rust-corelib-impl],
/// but with all additional clutter removed.
///
/// [rust-corelib-impl]: https://github.com/rust-lang/rust/blob/415d8fcc3e17f8c1324a81cf2aa7127b4fcfa32e/library/core/src/num/uint_macros.rs#L774
#[inline(always)] // Force copy of each invocation for optimization, see comments below
const fn _unchecked_ilog_inner(exp: Word, base: Word) -> u32 {
let mut n = 0;
let mut r = exp;
while r >= base {
r /= base;
n += 1;
}

n
}

/// Logarithm for given exponent and an arbitrary base, rounded
/// rounded down to nearest integer value.
///
/// Returns `None` if the exponent == 0, or if the base <= 1.
///
/// TODO: when <https://github.com/rust-lang/rust/issues/70887> is stabilized,
/// consider using that instead.
const fn checked_ilog(exp: Word, base: Word) -> Option<u32> {
if exp == 0 || base <= 1 {
return None;
}

// Generate separately optimized paths for some common and/or expensive bases.
// See <https://github.com/FuelLabs/fuel-vm/issues/150#issuecomment-1288797787> for benchmark.
Some(match base {
2 => _unchecked_ilog_inner(exp, 2),
3 => _unchecked_ilog_inner(exp, 3),
4 => _unchecked_ilog_inner(exp, 4),
5 => _unchecked_ilog_inner(exp, 5),
10 => _unchecked_ilog_inner(exp, 10),
n => _unchecked_ilog_inner(exp, n),
})
}

#[cfg(test)]
mod tests;
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use num_integer::Roots;
use rayon::prelude::*;

use super::{checked_ilog, checked_nth_root};
use super::checked_nth_root;

/// Check for https://github.com/FuelLabs/fuel-vm/issues/150
#[test]
fn mlog_rounding_issues() {
assert_eq!(checked_ilog(999, 10), Some(2));
assert_eq!(checked_ilog(1000, 10), Some(3));
assert_eq!(checked_ilog(1001, 10), Some(3));
assert_eq!(999u32.checked_ilog(10), Some(2));
assert_eq!(1000u32.checked_ilog(10), Some(3));
assert_eq!(1001u32.checked_ilog(10), Some(3));
}

/// Verify some subsets of possible inputs against a known-good implementation.
Expand Down

0 comments on commit c32292b

Please sign in to comment.