Skip to content

Commit

Permalink
Merge #225
Browse files Browse the repository at this point in the history
225: Refactor conversion methods to avoid floating points on `no_std` r=cuviper a=archseer

This might be better suited behind a new feature gate? We're trying to use `num-bigint` in a WASM project that's running on [CosmWasm](https://docs.cosmwasm.com/docs/0.16/). The code compiles fine, but when trying to execute the program it's rejected by the VM because it refuses to run bytecode containing floating point operations.

Turns out the codebase already does a good job of avoiding such operations with the `std` feature disabled, but it's still being used in `from_radix_digits_be`/`_le` to estimate the final result size. I've switched this out on the no std code path and it seems to run fine with this change.

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
  • Loading branch information
bors[bot] and archseer authored Feb 11, 2023
2 parents 10e2d96 + 6fa549e commit 6f2b8e0
Showing 1 changed file with 19 additions and 8 deletions.
27 changes: 19 additions & 8 deletions src/biguint/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,20 @@ fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
debug_assert!(!v.is_empty() && !radix.is_power_of_two());
debug_assert!(v.iter().all(|&c| u32::from(c) < radix));

// Estimate how big the result will be, so we can pre-allocate it.
#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
let big_digits = {
let radix_log2 = f64::from(radix).log2();
let bits = radix_log2 * v.len() as f64;
(bits / big_digit::BITS as f64).ceil()
};
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix.next_power_of_two()) as f64;
let big_digits = {
let radix_log2 = ilog2(radix.next_power_of_two()) as usize;
let bits = radix_log2 * v.len();
(bits / big_digit::BITS as usize) + 1
};

// Estimate how big the result will be, so we can pre-allocate it.
let bits = radix_log2 * v.len() as f64;
let big_digits = (bits / big_digit::BITS as f64).ceil();
let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0));

let (base, power) = get_radix_base(radix, big_digit::BITS);
Expand Down Expand Up @@ -657,12 +663,17 @@ pub(super) fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
debug_assert!(!u.is_zero() && !radix.is_power_of_two());

#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
let radix_digits = {
let radix_log2 = f64::from(radix).log2();
((u.bits() as f64) / radix_log2).ceil()
};
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix) as f64;
let radix_digits = {
let radix_log2 = ilog2(radix) as usize;
((u.bits() as usize) / radix_log2) + 1
};

// Estimate how big the result will be, so we can pre-allocate it.
let radix_digits = ((u.bits() as f64) / radix_log2).ceil();
let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0));

let mut digits = u.clone();
Expand Down

0 comments on commit 6f2b8e0

Please sign in to comment.