1 // Copyright John Maddock 2015.
3 // Use, modification and distribution are subject to the
4 // Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
9 #define _SCL_SECURE_NO_WARNINGS
12 #include <boost/multiprecision/cpp_int.hpp>
14 #include <boost/algorithm/string/case_conv.hpp>
15 #include <boost/random/mersenne_twister.hpp>
16 #include <boost/random/uniform_int.hpp>
22 #pragma warning(disable : 4127)
30 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
>
31 struct unchecked_type
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<MinBits
, MaxBits
, SignType
, Checked
, Allocator
>, ExpressionTemplates
> >
33 typedef boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<MinBits
, MaxBits
, SignType
, boost::multiprecision::unchecked
, Allocator
>, ExpressionTemplates
> type
;
39 typedef typename unchecked_type
<T
>::type unchecked_T
;
41 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;
43 static boost::random::uniform_int_distribution
<unsigned> ui(0, limbs
);
44 static boost::random::mt19937 gen
;
45 unchecked_T val
= gen();
46 unsigned lim
= ui(gen
);
47 for (unsigned i
= 0; i
< lim
; ++i
)
56 void test_round_trip_neg(T val
, const boost::mpl::true_
&)
58 // Try some negative values:
59 std::vector
<unsigned char> cv
;
62 export_bits(val
, std::back_inserter(cv
), 8, false);
63 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
64 BOOST_CHECK_EQUAL(-val
, newval
);
68 void test_round_trip_neg(const T
&, const boost::mpl::false_
&)
73 void test_round_trip(T val
)
75 std::vector
<unsigned char> cv
;
76 export_bits(val
, std::back_inserter(cv
), 8);
78 import_bits(newval
, cv
.begin(), cv
.end());
79 BOOST_CHECK_EQUAL(val
, newval
);
80 // Should get the same value if we reverse the bytes:
81 std::reverse(cv
.begin(), cv
.end());
83 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
84 BOOST_CHECK_EQUAL(val
, newval
);
85 // Also try importing via pointers as these may memcpy:
87 import_bits(newval
, &cv
[0], &cv
[0] + cv
.size(), 8, false);
88 BOOST_CHECK_EQUAL(val
, newval
);
91 export_bits(val
, std::back_inserter(cv
), 8, false);
92 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
93 BOOST_CHECK_EQUAL(val
, newval
);
94 std::reverse(cv
.begin(), cv
.end());
96 import_bits(newval
, cv
.begin(), cv
.end(), 8, true);
97 BOOST_CHECK_EQUAL(val
, newval
);
99 std::vector
<boost::uintmax_t> bv
;
100 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
);
101 import_bits(newval
, bv
.begin(), bv
.end());
102 BOOST_CHECK_EQUAL(val
, newval
);
103 // Should get the same value if we reverse the values:
104 std::reverse(bv
.begin(), bv
.end());
106 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
107 BOOST_CHECK_EQUAL(val
, newval
);
108 // Also try importing via pointers as these may memcpy:
110 import_bits(newval
, &bv
[0], &bv
[0] + bv
.size(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
111 BOOST_CHECK_EQUAL(val
, newval
);
114 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
, false);
115 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
116 BOOST_CHECK_EQUAL(val
, newval
);
118 // Try with an unconventional number of bits, to model some machine with guard bits:
121 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
- 3);
122 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
- 3);
123 BOOST_CHECK_EQUAL(val
, newval
);
126 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
- 3, false);
127 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
- 3, false);
128 BOOST_CHECK_EQUAL(val
, newval
);
131 export_bits(val
, std::back_inserter(cv
), 6);
132 import_bits(newval
, cv
.begin(), cv
.end(), 6);
133 BOOST_CHECK_EQUAL(val
, newval
);
136 export_bits(val
, std::back_inserter(cv
), 6, false);
137 import_bits(newval
, cv
.begin(), cv
.end(), 6, false);
138 BOOST_CHECK_EQUAL(val
, newval
);
140 test_round_trip_neg(val
, boost::mpl::bool_
<std::numeric_limits
<T
>::is_signed
>());
144 void test_round_trip()
146 std::cout
<< std::hex
;
147 std::cerr
<< std::hex
;
148 for (unsigned i
= 0; i
< 1000; ++i
)
150 T val
= generate_random
<T
>();
151 test_round_trip(val
);
155 // See https://github.com/boostorg/multiprecision/issues/21
157 bug
<< std::numeric_limits
<T
>::digits
- 1;
159 test_round_trip(bug
);
164 test_round_trip
<boost::multiprecision::cpp_int
>();
165 test_round_trip
<boost::multiprecision::checked_int1024_t
>();
166 test_round_trip
<boost::multiprecision::checked_uint512_t
>();
167 test_round_trip
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<64, 64, boost::multiprecision::unsigned_magnitude
, boost::multiprecision::checked
, void> > >();
168 test_round_trip
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<23, 23, boost::multiprecision::unsigned_magnitude
, boost::multiprecision::checked
, void> > >();
169 return boost::report_errors();