Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
PrevUpHomeNext

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] 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] 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

Note that this function is optimized for the case where the data can be memcpyed 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_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_ASSERT(f == g);
}

PrevUpHomeNext