stencillogic/astro-float

Convert BigFloat to BigUint (from num_bigint)

Janmajayamall opened this issue · 8 comments

Thanks for the lib! It has been immensely helpful.

I am running into issues converting a BigFloat instance to BigUint (from num_bigint). My naive try is

let mut consts = Consts::new().unwrap();

let mut value = BigFloat::from(1.2);

let (sign, radix_repr, ex) = value
  .round(0, ROUNDING_MODE)
  .convert_to_radix(astro_float::Radix::Dec, ROUNDING_MODE, &mut consts)
  .unwrap();
  
// Assume sign is always positive
let value_biguint = BigUint::from_radix_be(&radix_repr, 10).unwrap();

I though that setting to n to 0 (i.e. fractional digits are decimal) will round the value to 1, hence mantissa will 1 and exp will be 0. But this isn't the case. Probably I am misreding the docs. Can you point me to a function using which I can round the value towards 0 and mantissa will drop rounded-off digits?

round is the function that can round fractional part of a number.
What's the value of this ROUNDING_MODE ?

Also, rounding will not change exponent of a number, unless there was overflow during rounding.

What's the value of this ROUNDING_MODE ?

It is set to none - RoundingMode::None

Ok, so seems like the only way is to read the mantissa after rounding as a string. Drop off digits after decimal as per the exponent. Then parse the resulting string of digits into BigUint. Do you think there's a better way to do this?

This is what I came up with:

let mut consts = Consts::new().unwrap();

let mut value = AstroBFloat::from(1.2);

let (sign, radix_repr, mut ex) = value
    .round(0, ROUNDING_MODE)
    .convert_to_radix(astro_float::Radix::Dec, ROUNDING_MODE, &mut consts)
    .unwrap();

if ex < 0 {
    ex = 0;
}

// Assume sign is always positive
let value_biguint = BigUint::from_radix_be(&radix_repr[..ex as usize], 10).unwrap();

round() with RoundingMode::None has no effect: docs.

The most efficient way in my opinion is to get raw parts of big float, and then construct big integer from the mantissa slice after accomplishing required bit shift.

Sorry for late reply!

Is this what you had in mind ?

// PRECISION = 256
// MANTISSA_LEN = 4
let value = value.0.clone();
let (raw, _, s, _, _) = value.as_raw_parts().unwrap();
let exponent = value.exponent().unwrap();

let mut bits = exponent;
let mut index = MATISSA_LEN - 1;
let mut res = BigInt::zero();
while bits > 0 {
    res += (BigInt::from_u64(raw[index as usize]).unwrap())
        << (astro_float::WORD_BIT_SIZE * index);
    bits -= astro_float::WORD_BIT_SIZE as i32;
    index -= 1;
}
res >>= (PRECISION as i32) - exponent;
res = if s.is_negative() { res.neg() } else { res }

Closing the issue as it is not a bug.