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