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)
25 struct unchecked_type
{ typedef T type
; };
27 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
>
28 struct unchecked_type
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<MinBits
, MaxBits
, SignType
, Checked
, Allocator
>, ExpressionTemplates
> >
30 typedef boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<MinBits
, MaxBits
, SignType
, boost::multiprecision::unchecked
, Allocator
>, ExpressionTemplates
> type
;
37 typedef typename unchecked_type
<T
>::type unchecked_T
;
39 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;
41 static boost::random::uniform_int_distribution
<unsigned> ui(0, limbs
);
42 static boost::random::mt19937 gen
;
43 unchecked_T val
= gen();
44 unsigned lim
= ui(gen
);
45 for(unsigned i
= 0; i
< lim
; ++i
)
54 void test_round_trip_neg(T val
, const boost::mpl::true_
&)
56 // Try some negative values:
57 std::vector
<unsigned char> cv
;
60 export_bits(val
, std::back_inserter(cv
), 8, false);
61 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
62 BOOST_CHECK_EQUAL(-val
, newval
);
66 void test_round_trip_neg(const T
&, const boost::mpl::false_
&)
71 void test_round_trip(T val
)
73 std::vector
<unsigned char> cv
;
74 export_bits(val
, std::back_inserter(cv
), 8);
76 import_bits(newval
, cv
.begin(), cv
.end());
77 BOOST_CHECK_EQUAL(val
, newval
);
78 // Should get the same value if we reverse the bytes:
79 std::reverse(cv
.begin(), cv
.end());
81 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
82 BOOST_CHECK_EQUAL(val
, newval
);
83 // Also try importing via pointers as these may memcpy:
85 import_bits(newval
, &cv
[0], &cv
[0] + cv
.size(), 8, false);
86 BOOST_CHECK_EQUAL(val
, newval
);
89 export_bits(val
, std::back_inserter(cv
), 8, false);
90 import_bits(newval
, cv
.begin(), cv
.end(), 8, false);
91 BOOST_CHECK_EQUAL(val
, newval
);
92 std::reverse(cv
.begin(), cv
.end());
94 import_bits(newval
, cv
.begin(), cv
.end(), 8, true);
95 BOOST_CHECK_EQUAL(val
, newval
);
97 std::vector
<boost::uintmax_t> bv
;
98 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
);
99 import_bits(newval
, bv
.begin(), bv
.end());
100 BOOST_CHECK_EQUAL(val
, newval
);
101 // Should get the same value if we reverse the values:
102 std::reverse(bv
.begin(), bv
.end());
104 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
105 BOOST_CHECK_EQUAL(val
, newval
);
106 // Also try importing via pointers as these may memcpy:
108 import_bits(newval
, &bv
[0], &bv
[0] + bv
.size(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
109 BOOST_CHECK_EQUAL(val
, newval
);
112 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
, false);
113 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
, false);
114 BOOST_CHECK_EQUAL(val
, newval
);
116 // Try with an unconventional number of bits, to model some machine with guard bits:
119 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
- 3);
120 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
- 3);
121 BOOST_CHECK_EQUAL(val
, newval
);
124 export_bits(val
, std::back_inserter(bv
), std::numeric_limits
<boost::uintmax_t>::digits
- 3, false);
125 import_bits(newval
, bv
.begin(), bv
.end(), std::numeric_limits
<boost::uintmax_t>::digits
- 3, false);
126 BOOST_CHECK_EQUAL(val
, newval
);
129 export_bits(val
, std::back_inserter(cv
), 6);
130 import_bits(newval
, cv
.begin(), cv
.end(), 6);
131 BOOST_CHECK_EQUAL(val
, newval
);
134 export_bits(val
, std::back_inserter(cv
), 6, false);
135 import_bits(newval
, cv
.begin(), cv
.end(), 6, false);
136 BOOST_CHECK_EQUAL(val
, newval
);
138 test_round_trip_neg(val
, boost::mpl::bool_
<std::numeric_limits
<T
>::is_signed
>());
142 void test_round_trip()
144 std::cout
<< std::hex
;
145 std::cerr
<< std::hex
;
146 for(unsigned i
= 0; i
< 1000; ++i
)
148 T val
= generate_random
<T
>();
149 test_round_trip(val
);
153 // See https://github.com/boostorg/multiprecision/issues/21
155 bug
<< std::numeric_limits
<T
>::digits
- 1;
157 test_round_trip(bug
);
162 test_round_trip
<boost::multiprecision::cpp_int
>();
163 test_round_trip
<boost::multiprecision::checked_int1024_t
>();
164 test_round_trip
<boost::multiprecision::checked_uint512_t
>();
165 test_round_trip
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<64, 64, boost::multiprecision::unsigned_magnitude
, boost::multiprecision::checked
, void> > >();
166 test_round_trip
<boost::multiprecision::number
<boost::multiprecision::cpp_int_backend
<23, 23, boost::multiprecision::unsigned_magnitude
, boost::multiprecision::checked
, void> > >();
167 return boost::report_errors();