converting from BigInt to BitArray

408 Views Asked by At

what would be best way to convert object using rust from bigint (BigInt) to bits (BitArray<217>) also in reverse (example below)

using binary to decimal calculator I verified by hand that bigint and bits equate


let bigint = BigInt::parse_bytes("141644482300309102636663083870634002744809361056209271964506585197".as_ref(), 10);

to 

let bits = BitArray::new( [1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1]);

crates ref.

for BigInt: https://crates.io/crates/num-bigint (num-bigint = "0.4.3")

for BitArray: https://crates.io/crates/bitarray (bitarray = "0.10.0")

1

There are 1 best solutions below

10
Finomnis On BEST ANSWER

Couple of misconceptions:

  • You can't convert a size known at runtime (BigInt) to a size known at compile time (BitArray)
  • BigInt is signed, but at no point during your conversion you consider signedness. You probably want to use BigUint instead if you want to ignore signedness.
  • Your BitArray for comparison only consists of 1 and 0 values. bitarray::BitArray, however, is meant as bytes, meaning, each value is 8 bits, valued from 0 to 255. If you convert it, the value is actually BitArray::new([1, 88, 81, 147, 230, 162, 120, 203, 210, 232, 153, 239, 115, 92, 222, 74, 147, 18, 216, 202, 55, 207, 181, 126, 72, 92, 248, 109]) and 28 long.
  • bitarray::BitArray does not seem to be able to iterate over it bitwise, so I don't know how useful this library is for you. The fact that it forces compile time size is also not compatible with your usecase. You should probably choose a different library. The entire concept of a "bit array" is probably not what you want, you probably want a "bit vector" instead with a runtime size.

That said, bitarray consists of packed bits, meaning 8 bits per value (or more). If you want a pure Vec<bool>, you don't need any of this, you can directly convert it to that:

use num_bigint::BigUint;

fn main() {
    let bigint = BigUint::parse_bytes(
        "141644482300309102636663083870634002744809361056209271964506585197".as_ref(),
        10,
    )
    .unwrap();

    let bits = bigint
        .to_bytes_be()
        .into_iter()
        .flat_map(|val| {
            [
                (val >> 7) & 1,
                (val >> 6) & 1,
                (val >> 5) & 1,
                (val >> 4) & 1,
                (val >> 3) & 1,
                (val >> 2) & 1,
                (val >> 1) & 1,
                (val >> 0) & 1,
            ]
            .into_iter()
        })
        .collect::<Vec<_>>();

    println!("{:?}", bits);
}
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1]

Not that the value you give seems to be little-endian, while this one is big-endian.


Here is an even shorter version, utilizing the crate bitvec:

use bitvec::{order::Msb0, vec::BitVec};
use num_bigint::BigUint;

fn main() {
    let bigint = BigUint::parse_bytes(
        "141644482300309102636663083870634002744809361056209271964506585197".as_ref(),
        10,
    )
    .unwrap();

    let bits: BitVec<_, Msb0> = BitVec::from_vec(bigint.to_bytes_be());
    println!("{}", bits);
}
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1]

Or, if you prefer little endian:

use bitvec::{order::Lsb0, vec::BitVec};
use num_bigint::BigUint;

fn main() {
    let bigint = BigUint::parse_bytes(
        "141644482300309102636663083870634002744809361056209271964506585197".as_ref(),
        10,
    )
    .unwrap();

    let bits: BitVec<_, Lsb0> = BitVec::from_vec(bigint.to_bytes_le());
    println!("{}", bits);
}
[1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]

Note that while bits is packed, you can still iterate over it bitwise. If you want to convert it to a u8 vector, do:

let bits_u8: Vec<u8> = bits.into_iter().map(Into::into).collect();