Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / multiprecision / test / test_cpp_int_import_export.cpp
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
26 {
27    typedef T type;
28 };
29
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> >
32 {
33    typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> type;
34 };
35
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);
44    static boost::random::mt19937                            gen;
45    unchecked_T                                              val = gen();
46    unsigned                                                 lim = ui(gen);
47    for (unsigned i = 0; i < lim; ++i)
48    {
49       val *= (gen.max)();
50       val += gen();
51    }
52    return val;
53 }
54
55 template <class T>
56 void test_round_trip_neg(T val, const boost::mpl::true_&)
57 {
58    // Try some negative values:
59    std::vector<unsigned char> cv;
60    T                          newval;
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>
68 void test_round_trip_neg(const T&, const boost::mpl::false_&)
69 {
70 }
71
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
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());
105    newval = 0;
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:
109    newval = 0;
110    import_bits(newval, &bv[0], &bv[0] + bv.size(), std::numeric_limits<boost::uintmax_t>::digits, false);
111    BOOST_CHECK_EQUAL(val, newval);
112
113    bv.clear();
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);
117    //
118    // Try with an unconventional number of bits, to model some machine with guard bits:
119    //
120    bv.clear();
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);
124
125    bv.clear();
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);
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
140    test_round_trip_neg(val, boost::mpl::bool_<std::numeric_limits<T>::is_signed>());
141 }
142
143 template <class T>
144 void test_round_trip()
145 {
146    std::cout << std::hex;
147    std::cerr << std::hex;
148    for (unsigned i = 0; i < 1000; ++i)
149    {
150       T val = generate_random<T>();
151       test_round_trip(val);
152    }
153    //
154    // Bug cases.
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);
160 }
161
162 int main()
163 {
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();
170 }