num-bigint icon indicating copy to clipboard operation
num-bigint copied to clipboard

Add to_slice and to_vec functions

Open uzytkownik opened this issue 7 years ago • 7 comments

I needed to convert to/from mpz_t. While converting into is relativly simple due to from_slice function the invert requires allocation of array with base 28 making it less efficient (requiring 2 copies and 2 convertions from/to 8 bit instead of 1 or 0). Those functions would allow inspecting representation of function without need of allocating and creating additional copies.

uzytkownik avatar Jan 03 '18 07:01 uzytkownik

I hesitate to expose the internal representation so much, for the borrowed slice especially.

How would you feel about some kind of iterator instead? We could make it return bytes or even larger units, without having to allocate the full conversion.

cuviper avatar Jan 07 '18 03:01 cuviper

That would not solve the problem fully due to mpz_export/mpz_import functions. GMP documents internals only partially (namely - there are some compile-time constants) so I guess it should work assuming some support for nails,

uzytkownik avatar Jan 07 '18 03:01 uzytkownik

Perhaps we could frame this in a way that doesn't commit to a particular representation? Like:

impl BigUint {
    // Returns `(count, order, size, endian, nails, ptr)` in the style of `mpz_import`
    fn export_raw<F, T>(&self, f: F) -> (usize, c_int, usize, c_int, usize, *const c_void);
}

Obviously that's tailored directly for GMP, but I'm not sure how to generalize this idea.

cuviper avatar Mar 04 '18 01:03 cuviper

If what is required is conversion to mpz_t, an iterator could work, considering that GMP does document its internal representation. As a note, I don't think nails need to be supported, considering that if I'm not mistaken, compiling GMP with nails has been broken since late in the 4.* series (that's ancient). I hacked up something assuming that BigUint has some digits() method that gives an iterator with the digits of our requested size (u32 or u64), least significant first. I did not test it, this is just to give an idea of how to go about it:

use gmp_mpfr_sys::gmp;
use std::os::raw::c_int;
use std::slice;
fn copy_to_gmp(src: &BigUint, dst: &mut gmp::mpz_t) {
    assert_eq!(gmp::NAIL_BITS, 0, "nails not supported");
    let bits = src.bits();
    dst.size = 0;
    if bits == 0 {
        return;
    }
    let limb_bits = gmp::LIMB_BITS as usize;
    let limb_count = (bits + limb_bits - 1) / limb_bits;
    let limbs = unsafe {
        gmp::_mpz_realloc(mpz_t, limb_count);
        slice::from_raw_parts_mut(dst.d, limb_count)
    };
    // limb_t is either u32 or u64
    let mut digits = src.digits::<gmp::limb_t>();
    for i in limbs.iter_mut() {
        *i = digits.next().expect("not enough digits");
    }
    assert!(digits.next().is_none(), "too many digits");
    dst.size = limb_count as c_int;
    assert!(dst.size > 0 && dst.size as usize == limb_count, "overflow");
}

tspiteri avatar Mar 18 '18 22:03 tspiteri

Another data point: it would be great to have the limbs exposed as an iterator

dignifiedquire avatar Jul 17 '18 21:07 dignifiedquire

I've the same issue, I need to access the internal &[u32] slice. There is a from_slice, so a to_slice function returning a Vec would be nice and doesn't require to commit to a predefined internal representation.

For performance, it would be nice to have an iterable version of it or a non documented version (like as_slice).

Speedy37 avatar Aug 16 '19 19:08 Speedy37

I'd like either a function that returned the underlying slice or an iterator too.

expenses avatar Oct 15 '19 08:10 expenses