]>
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 | |
92f5a8d4 | 9 | #define _SCL_SECURE_NO_WARNINGS |
7c673cae FG |
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 | |
92f5a8d4 | 22 | #pragma warning(disable : 4127) |
7c673cae FG |
23 | #endif |
24 | template <class T> | |
92f5a8d4 TL |
25 | struct unchecked_type |
26 | { | |
27 | typedef T type; | |
28 | }; | |
7c673cae | 29 | |
1e59de90 | 30 | template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates> |
7c673cae FG |
31 | struct unchecked_type<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> > |
32 | { | |
33 | typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> type; | |
34 | }; | |
35 | ||
7c673cae FG |
36 | template <class T> |
37 | T generate_random() | |
38 | { | |
39 | typedef typename unchecked_type<T>::type unchecked_T; | |
40 | ||
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; | |
42 | ||
43 | static boost::random::uniform_int_distribution<unsigned> ui(0, limbs); | |
92f5a8d4 TL |
44 | static boost::random::mt19937 gen; |
45 | unchecked_T val = gen(); | |
46 | unsigned lim = ui(gen); | |
47 | for (unsigned i = 0; i < lim; ++i) | |
7c673cae FG |
48 | { |
49 | val *= (gen.max)(); | |
50 | val += gen(); | |
51 | } | |
52 | return val; | |
53 | } | |
54 | ||
55 | template <class T> | |
1e59de90 | 56 | void test_round_trip_neg(T val, const std::integral_constant<bool, true>&) |
7c673cae FG |
57 | { |
58 | // Try some negative values: | |
59 | std::vector<unsigned char> cv; | |
92f5a8d4 | 60 | T newval; |
7c673cae FG |
61 | val = -val; |
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); | |
65 | } | |
66 | ||
67 | template <class T> | |
1e59de90 | 68 | void test_round_trip_neg(const T&, const std::integral_constant<bool, false>&) |
7c673cae FG |
69 | { |
70 | } | |
71 | ||
b32b8144 FG |
72 | template <class T> |
73 | void test_round_trip(T val) | |
74 | { | |
75 | std::vector<unsigned char> cv; | |
76 | export_bits(val, std::back_inserter(cv), 8); | |
77 | T newval; | |
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()); | |
82 | newval = 0; | |
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: | |
86 | newval = 0; | |
87 | import_bits(newval, &cv[0], &cv[0] + cv.size(), 8, false); | |
88 | BOOST_CHECK_EQUAL(val, newval); | |
89 | ||
90 | cv.clear(); | |
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()); | |
95 | newval = 0; | |
96 | import_bits(newval, cv.begin(), cv.end(), 8, true); | |
97 | BOOST_CHECK_EQUAL(val, newval); | |
98 | ||
1e59de90 TL |
99 | std::vector<std::uintmax_t> bv; |
100 | export_bits(val, std::back_inserter(bv), std::numeric_limits<std::uintmax_t>::digits); | |
b32b8144 FG |
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()); | |
105 | newval = 0; | |
1e59de90 | 106 | import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<std::uintmax_t>::digits, false); |
b32b8144 FG |
107 | BOOST_CHECK_EQUAL(val, newval); |
108 | // Also try importing via pointers as these may memcpy: | |
109 | newval = 0; | |
1e59de90 | 110 | import_bits(newval, &bv[0], &bv[0] + bv.size(), std::numeric_limits<std::uintmax_t>::digits, false); |
b32b8144 FG |
111 | BOOST_CHECK_EQUAL(val, newval); |
112 | ||
113 | bv.clear(); | |
1e59de90 TL |
114 | export_bits(val, std::back_inserter(bv), std::numeric_limits<std::uintmax_t>::digits, false); |
115 | import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<std::uintmax_t>::digits, false); | |
b32b8144 FG |
116 | BOOST_CHECK_EQUAL(val, newval); |
117 | // | |
118 | // Try with an unconventional number of bits, to model some machine with guard bits: | |
119 | // | |
120 | bv.clear(); | |
1e59de90 TL |
121 | export_bits(val, std::back_inserter(bv), std::numeric_limits<std::uintmax_t>::digits - 3); |
122 | import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<std::uintmax_t>::digits - 3); | |
b32b8144 FG |
123 | BOOST_CHECK_EQUAL(val, newval); |
124 | ||
125 | bv.clear(); | |
1e59de90 TL |
126 | export_bits(val, std::back_inserter(bv), std::numeric_limits<std::uintmax_t>::digits - 3, false); |
127 | import_bits(newval, bv.begin(), bv.end(), std::numeric_limits<std::uintmax_t>::digits - 3, false); | |
b32b8144 FG |
128 | BOOST_CHECK_EQUAL(val, newval); |
129 | ||
130 | cv.clear(); | |
131 | export_bits(val, std::back_inserter(cv), 6); | |
132 | import_bits(newval, cv.begin(), cv.end(), 6); | |
133 | BOOST_CHECK_EQUAL(val, newval); | |
134 | ||
135 | cv.clear(); | |
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); | |
139 | ||
1e59de90 | 140 | test_round_trip_neg(val, std::integral_constant<bool, std::numeric_limits<T>::is_signed>()); |
b32b8144 FG |
141 | } |
142 | ||
7c673cae FG |
143 | template <class T> |
144 | void test_round_trip() | |
145 | { | |
146 | std::cout << std::hex; | |
147 | std::cerr << std::hex; | |
92f5a8d4 | 148 | for (unsigned i = 0; i < 1000; ++i) |
7c673cae FG |
149 | { |
150 | T val = generate_random<T>(); | |
b32b8144 | 151 | test_round_trip(val); |
7c673cae | 152 | } |
b32b8144 | 153 | // |
92f5a8d4 | 154 | // Bug cases. |
b32b8144 FG |
155 | // See https://github.com/boostorg/multiprecision/issues/21 |
156 | T bug(1); | |
157 | bug << std::numeric_limits<T>::digits - 1; | |
158 | --bug; | |
159 | test_round_trip(bug); | |
7c673cae FG |
160 | } |
161 | ||
162 | int main() | |
163 | { | |
164 | test_round_trip<boost::multiprecision::cpp_int>(); | |
165 | test_round_trip<boost::multiprecision::checked_int1024_t>(); | |
92f5a8d4 | 166 | test_round_trip<boost::multiprecision::checked_uint512_t>(); |
7c673cae FG |
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(); | |
170 | } |