1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// Copyright John Maddock 2015.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef _MSC_VER
# define _SCL_SECURE_NO_WARNINGS
#endif
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include "test.hpp"
#include <iostream>
#include <iomanip>
#ifdef BOOST_MSVC
#pragma warning(disable:4127)
#endif
template <class T>
struct unchecked_type { typedef T type; };
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
struct unchecked_type<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >
{
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> type;
};
template <class T>
T generate_random()
{
typedef typename unchecked_type<T>::type unchecked_T;
static const unsigned limbs = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits / std::numeric_limits<unsigned>::digits + 3 : 20;
static boost::random::uniform_int_distribution<unsigned> ui(0, limbs);
static boost::random::mt19937 gen;
unchecked_T val = gen();
unsigned lim = ui(gen);
for(unsigned i = 0; i < lim; ++i)
{
val *= (gen.max)();
val += gen();
}
return val;
}
template <class T>
void test_round_trip_neg(T val, const boost::mpl::true_&)
{
// Try some negative values:
std::vector<unsigned char> cv;
T newval;
val = -val;
export_bits(val, std::back_inserter(cv), 8, false);
import_bits(newval, cv.begin(), cv.end(), 8, false);
BOOST_CHECK_EQUAL(-val, newval);
}
template <class T>
void test_round_trip_neg(const T&, const boost::mpl::false_&)
{
}
template <class T>
void test_round_trip()
{
std::cout << std::hex;
std::cerr << std::hex;
for(unsigned i = 0; i < 1000; ++i)
{
T val = generate_random<T>();
std::vector<unsigned char> cv;
export_bits(val, std::back_inserter(cv), 8);
T newval;
import_bits(newval, cv.begin(), cv.end());
BOOST_CHECK_EQUAL(val, newval);
// Should get the same value if we reverse the bytes:
std::reverse(cv.begin(), cv.end());
newval = 0;
import_bits(newval, cv.begin(), cv.end(), 8, false);
BOOST_CHECK_EQUAL(val, newval);
// Also try importing via pointers as these may memcpy:
newval = 0;
import_bits(newval, &cv[0], &cv[0] + cv.size(), 8, false);
BOOST_CHECK_EQUAL(val, newval);
cv.clear();
export_bits(val, std::back_inserter(cv), 8, false);
import_bits(newval, cv.begin(), cv.end(), 8, false);
BOOST_CHECK_EQUAL(val, newval);
std::reverse(cv.begin(), cv.end());
newval = 0;
import_bits(newval, cv.begin(), cv.end(), 8, true);
BOOST_CHECK_EQUAL(val, newval);
std::vector<boost::uintmax_t> bv;
export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits);
import_bits(newval, bv.begin(), bv.end());
BOOST_CHECK_EQUAL(val, newval);
// Should get the same value if we reverse the values:
std::reverse(bv.begin(), bv.end());
newval = 0;
import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits, false);
BOOST_CHECK_EQUAL(val, newval);
// Also try importing via pointers as these may memcpy:
newval = 0;
import_bits(newval, &bv[0], &bv[0] + bv.size(), std::numeric_limits<boost::uintmax_t>::digits, false);
BOOST_CHECK_EQUAL(val, newval);
bv.clear();
export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits, false);
import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits, false);
BOOST_CHECK_EQUAL(val, newval);
//
// Try with an unconventional number of bits, to model some machine with guard bits:
//
bv.clear();
export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits - 3);
import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits - 3);
BOOST_CHECK_EQUAL(val, newval);
bv.clear();
export_bits(val, std::back_inserter(bv), std::numeric_limits<boost::uintmax_t>::digits - 3, false);
import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<boost::uintmax_t>::digits - 3, false);
BOOST_CHECK_EQUAL(val, newval);
cv.clear();
export_bits(val, std::back_inserter(cv), 6);
import_bits(newval, cv.begin(), cv.end(), 6);
BOOST_CHECK_EQUAL(val, newval);
cv.clear();
export_bits(val, std::back_inserter(cv), 6, false);
import_bits(newval, cv.begin(), cv.end(), 6, false);
BOOST_CHECK_EQUAL(val, newval);
test_round_trip_neg(val, boost::mpl::bool_<std::numeric_limits<T>::is_signed>());
}
}
int main()
{
test_round_trip<boost::multiprecision::cpp_int>();
test_round_trip<boost::multiprecision::checked_int1024_t>();
test_round_trip<boost::multiprecision::checked_uint512_t >();
test_round_trip<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::checked, void> > >();
test_round_trip<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<23, 23, boost::multiprecision::unsigned_magnitude, boost::multiprecision::checked, void> > >();
return boost::report_errors();
}
|