I need to decode/encode cpp_int values from/into byte arrays. The encoding must be shortest little endian two's complement representation of the value. For example:
00 = 0 01 = 1 ff = -1 ff:7f = 32767 01:80 = -32767 00:80:00 = 32768 00:80 = -32768 01:80:00 = 32769 ff:7f:ff = -32769 ff:ff:ef:9c:d2:40:43:da:4f:40:6b:06:6a:cd:92:c2:93:bf:a4:5c:c3:f1:29:63:1d = 184467440737095516151844674407370955161518446744073709551615 01:00:10:63:2d:bf:bc:25:b0:bf:94:f9:95:32:6d:3d:6c:40:5b:a3:3c:0e:d6:9c:e2 = -184467440737095516151844674407370955161518446744073709551615
I found a way to archive my goal (see below), but it seems way to complex and too inefficient. For encoding I basically converting the cpp_int to a uint8_t to get 8 bit and then shift the cpp_int by 8, creating a new cpp_int... Twice (once to compute it's length, again to encode it). For decoding I already shift the byte read to the "right" position and "|=" it into the existing cpp_int.
Isn't there an easier way access the binary representation of an cpp_int?
If you don't mind using undocumented internal functions you can access the underlying array of limbs via: my_int.backend().limbs() which returns a pointer to an array of unsigned integers of length my_int.backend().size(). Note that the type of unsigned integer used varies by platform, and also by the template arguments passed to cpp_int_backend - but if you handle the result via a template function that should take care of that? HTH, John.
#include <iostream> #include
using namespace std; using namespace boost::multiprecision;
size_t binLength( cpp_int value ) { if ( value.is_zero() ) return 1; if ( value.sign() < 0 ) value = ~ value; size_t length = 0; uint8_t lastByte; do { lastByte = value.convert_to
(); value >>= 8; length ++; } while ( ! value.is_zero() ); if ( lastByte >= 0x80 ) length ++; return length; } void binEncode( cpp_int value, uint8_t* output, size_t length ) { if ( value.is_zero() ) *output = 0; else if ( value.sign() > 0 ) while ( length -- > 0 ) { *( output ++ ) = value.convert_to
(); value >>= 8; } else { value = ~ value; while ( length -- > 0 ) { *( output ++ ) = ~ value.convert_to (); value >>= 8; } } } cpp_int binDecode( uint8_t* input, size_t length ) { boost::multiprecision::cpp_int result( 0 ); int bits = - 8; while ( length -- > 1 ) result |= (boost::multiprecision::cpp_int) *( input ++ ) << ( bits += 8 ); uint8_t a = *( input ++ ); result |= (boost::multiprecision::cpp_int) a << ( bits += 8 ); if ( a >= 0x80 ) result |= (boost::multiprecision::cpp_int) - 1 << ( bits + 8 ); return result; }
void test( string s ) { cpp_int x( s ); uint8_t buffer[ 100 ]; size_t length = binLength( x ), index = 0; binEncode( x, buffer, length ); cpp_int y = binDecode( buffer, length ); cout << hex << setw( 2 ) << setfill( '0' ) << (int) buffer[ 0 ]; while ( -- length > 0 ) cout << ':' << setw( 2 ) << setfill( '0' ) << (int) buffer[ ++ index ]; cout << " = " << dec << setw( 1 ) << x << endl; if ( x != y ) cerr << "failed" << endl; }
int main( int argc, const char* argv[] ) { test( "0" ); test( "1" ); test( "-1" ); test( "32767" ); test( "-32767" ); test( "32768" ); test( "-32768" ); test( "32769" ); test( "-32769" ); test( "184467440737095516151844674407370955161518446744073709551615" ); test( "-184467440737095516151844674407370955161518446744073709551615" ); }
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users