]>
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 | ||
b32b8144 FG |
70 | template <class T> |
71 | void test_round_trip(T val) | |
72 | { | |
73 | std::vector<unsigned char> cv; | |
74 | export_bits(val, std::back_inserter(cv), 8); | |
75 | T newval; | |
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()); | |
80 | newval = 0; | |
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: | |
84 | newval = 0; | |
85 | import_bits(newval, &cv[0], &cv[0] + cv.size(), 8, false); | |
86 | BOOST_CHECK_EQUAL(val, newval); | |
87 | ||
88 | cv.clear(); | |
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()); | |
93 | newval = 0; | |
94 | import_bits(newval, cv.begin(), cv.end(), 8, true); | |
95 | BOOST_CHECK_EQUAL(val, newval); | |
96 | ||
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()); | |
103 | newval = 0; | |
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: | |
107 | newval = 0; | |
108 | import_bits(newval, &bv[0], &bv[0] + bv.size(), std::numeric_limits<boost::uintmax_t>::digits, false); | |
109 | BOOST_CHECK_EQUAL(val, newval); | |
110 | ||
111 | bv.clear(); | |
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); | |
115 | // | |
116 | // Try with an unconventional number of bits, to model some machine with guard bits: | |
117 | // | |
118 | bv.clear(); | |
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); | |
122 | ||
123 | bv.clear(); | |
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); | |
127 | ||
128 | cv.clear(); | |
129 | export_bits(val, std::back_inserter(cv), 6); | |
130 | import_bits(newval, cv.begin(), cv.end(), 6); | |
131 | BOOST_CHECK_EQUAL(val, newval); | |
132 | ||
133 | cv.clear(); | |
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); | |
137 | ||
138 | test_round_trip_neg(val, boost::mpl::bool_<std::numeric_limits<T>::is_signed>()); | |
139 | } | |
140 | ||
7c673cae FG |
141 | template <class T> |
142 | void test_round_trip() | |
143 | { | |
144 | std::cout << std::hex; | |
145 | std::cerr << std::hex; | |
146 | for(unsigned i = 0; i < 1000; ++i) | |
147 | { | |
148 | T val = generate_random<T>(); | |
b32b8144 | 149 | test_round_trip(val); |
7c673cae | 150 | } |
b32b8144 FG |
151 | // |
152 | // Bug cases. | |
153 | // See https://github.com/boostorg/multiprecision/issues/21 | |
154 | T bug(1); | |
155 | bug << std::numeric_limits<T>::digits - 1; | |
156 | --bug; | |
157 | test_round_trip(bug); | |
7c673cae FG |
158 | } |
159 | ||
160 | int main() | |
161 | { | |
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(); | |
168 | } | |
169 |