| Home | Libraries | People | FAQ | More

### Importing and Exporting Data to and from `cpp_int` and `cpp_bin_float`

Any integer number type that uses `cpp_int_backend` as its implementation layer can import or export its bits via two non-member functions:

    template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
              expression_template_option ExpressionTemplates, class OutputIterator>
    OutputIterator export_bits(
       const number<const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
       OutputIterator out,
       unsigned chunk_size,
       bool msv_first = true);

    template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
              expression_template_option ExpressionTemplates, class Iterator>
    number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
       import_bits(
          number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
          Iterator i,
          Iterator j,
          unsigned chunk_size = 0,
          bool msv_first = true);

These functions are designed for data-interchange with other storage formats, and since cpp_bin_float uses cpp_int internally, by extension they can be used for floating-point numbers based on that backend as well (see example below). Parameters and use are as follows:

    template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
              expression_template_option ExpressionTemplates, class OutputIterator>
    OutputIterator export_bits(
       const number<const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
       OutputIterator out,
       unsigned chunk_size,
       bool msv_first = true);

Exports the absolute value of `val` to OutputIterator `out`. The function will write `chunk_size` bits at a time to the OutputIterator, and if `msv_first` is true, will write the most-significant block first. Byte and bit order within each `chunk_size` block is always in the machines native format. Further, each block is stored in a `std::uintmax_t` when it's assigned to `*out`.

| Note
Unfortunately, the standard's OutputIterator concept provides no means of deducing the type to output since `std::iterator_traits<OutputIteratorType>::value_type` is type `void`. This is why the bit count for each block has to be specified manually. It may also result in compiler warnings about the value being narrowed.

| Tip
If you're exporting to non-native byte layout, then use Boost.Endian to create a custom OutputIterator that reverses the byte order of each chunk prior to actually storing the result.

    template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
              expression_template_option ExpressionTemplates, class ForwardIterator>
    number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
       import_bits(
          number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
          ForwardIterator i,
          ForwardIterator j,
          unsigned chunk_size = 0,
          bool msv_first = true);

Imports bits from the iterator range [i,j) and stores them in `val` to produce an unsigned result (if the result is to be signed you will need to handle that separately). When `msv_first` is true, takes `*i` as the most significant chunk. Assumes there are `chunk_size` bits in each value read from the iterator range, and that these are in machine native bit/byte order. When `chunk_size` is zero, then assumes that each chunk contains `std::numeric_limits<std::iterator_traits<ForwardIterator>::value_type>::digits`, note that this will give the wrong result if dereferencing the iterators leads to a signed-integer type, and the sign bit is significant (be particularly careful if you expect type `char` to contain 8-bit values, as by default it will extract only 7-bits at a time if `char` is signed). As with exporting, if the external data is to be in a non-native byte order (within each chunk), then you will need to create an iterator adaptor that presents it in native order (see Boost.Endian).

| Note
Note that this function is optimized for the case where the data can be `memcpy`ed from the source to the integer - in this case both iterators much be pointers, and everything must be little-endian.

##### Examples

In this simple example, we'll import/export the bits of a cpp_int to a vector of 8-bit unsigned values:

    #include <boost/multiprecision/cpp_int.hpp>
    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <iterator>

    int main()
    {
       using boost::multiprecision::cpp_int;
       // Create a cpp_int with just a couple of bits set:
       cpp_int i;
       bit_set(i, 5000); // set the 5000'th bit
       bit_set(i, 200);
       bit_set(i, 50);
       // export into 8-bit unsigned values, most significant bit first:
       std::vector<unsigned char> v;
       export_bits(i, std::back_inserter(v), 8);
       // import back again, and check for equality:
       cpp_int j;
       import_bits(j, v.begin(), v.end());
       BOOST_MP_ASSERT(i == j);
    }

Importing or exporting cpp_bin_float is similar, but we must proceed via an intermediate integer:

    #include <boost/multiprecision/cpp_bin_float.hpp>
    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <iterator>

    int main()
    {
       using boost::multiprecision::cpp_bin_float_100;
       using boost::multiprecision::cpp_int;
       // Create a cpp_bin_float to import/export:
       cpp_bin_float_100 f(1);
       f /= 3;
       // export into 8-bit unsigned values, most significant bit first:
       std::vector<unsigned char> v;
       export_bits(cpp_int(f.backend().bits()), std::back_inserter(v), 8);
       // Grab the exponent as well:
       int e = f.backend().exponent();
       // Import back again, and check for equality, we have to proceed via
       // an intermediate integer:
       cpp_int i;
       import_bits(i, v.begin(), v.end());
       cpp_bin_float_100 g(i);
       g.backend().exponent() = e;
       BOOST_MP_ASSERT(f == g);
    }