1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5
6 //
7 // Compare arithmetic results using fixed_int to GMP results.
8 //
9
10 #ifdef _MSC_VER
11 #define _SCL_SECURE_NO_WARNINGS
12 #endif
13
14 #include <boost/multiprecision/cpp_int.hpp>
15 #include <boost/random/mersenne_twister.hpp>
16 #include <boost/random/uniform_int.hpp>
17 #include <boost/timer.hpp>
18 #include "test.hpp"
19
20 #include <iostream>
21 #include <iomanip>
22 #include <sstream>
23 #include <boost/archive/text_iarchive.hpp>
24 #include <boost/archive/text_oarchive.hpp>
25 #include <boost/archive/binary_iarchive.hpp>
26 #include <boost/archive/binary_oarchive.hpp>
27 #include <boost/archive/xml_iarchive.hpp>
28 #include <boost/archive/xml_oarchive.hpp>
29 #include <boost/exception/all.hpp>
30
31 template <class T>
generate_random(unsigned bits_wanted)32 T generate_random(unsigned bits_wanted)
33 {
34 static boost::random::mt19937 gen;
35 typedef boost::random::mt19937::result_type random_type;
36
37 T max_val;
38 unsigned digits;
39 if (std::numeric_limits<T>::is_bounded && (bits_wanted == (unsigned)std::numeric_limits<T>::digits))
40 {
41 max_val = (std::numeric_limits<T>::max)();
42 digits = std::numeric_limits<T>::digits;
43 }
44 else
45 {
46 max_val = T(1) << bits_wanted;
47 digits = bits_wanted;
48 }
49
50 unsigned bits_per_r_val = std::numeric_limits<random_type>::digits - 1;
51 while ((random_type(1) << bits_per_r_val) > (gen.max)())
52 --bits_per_r_val;
53
54 unsigned terms_needed = digits / bits_per_r_val + 1;
55
56 T val = 0;
57 for (unsigned i = 0; i < terms_needed; ++i)
58 {
59 val *= (gen.max)();
60 val += gen();
61 }
62 val %= max_val;
63 if (!val)
64 val = 1;
65 return val;
66 }
67
68 template <class T>
test_neg(const T & x,const boost::mpl::true_ &)69 void test_neg(const T& x, const boost::mpl::true_&)
70 {
71 T val = -x;
72 #ifndef BOOST_NO_EXCEPTIONS
73 try
74 {
75 #endif
76 T val2;
77 {
78 std::stringstream ss;
79 boost::archive::text_oarchive oa(ss);
80 oa << static_cast<const T&>(val);
81 boost::archive::text_iarchive ia(ss);
82 ia >> val2;
83 BOOST_CHECK_EQUAL(val, val2);
84 }
85 {
86 std::stringstream ss;
87 boost::archive::binary_oarchive ob(ss);
88 ob << static_cast<const T&>(val);
89 boost::archive::binary_iarchive ib(ss);
90 ib >> val2;
91 BOOST_CHECK_EQUAL(val, val2);
92 }
93 {
94 std::stringstream ss;
95 {
96 boost::archive::xml_oarchive ob(ss);
97 ob << boost::serialization::make_nvp("value", static_cast<const T&>(val));
98 }
99 boost::archive::xml_iarchive ib(ss);
100 ib >> boost::serialization::make_nvp("value", val2);
101 BOOST_CHECK_EQUAL(val, val2);
102 }
103 #ifndef BOOST_NO_EXCEPTIONS
104 }
105 catch (const boost::exception& e)
106 {
107 std::cout << "Caught boost::exception with:\n";
108 std::cout << diagnostic_information(e);
109 }
110 catch (const std::exception& e)
111 {
112 std::cout << "Caught std::exception with:\n";
113 std::cout << e.what() << std::endl;
114 }
115 #endif
116 }
117 template <class T>
test_neg(const T &,const boost::mpl::false_ &)118 void test_neg(const T&, const boost::mpl::false_&) {}
119
120 template <class T>
test()121 void test()
122 {
123 using namespace boost::multiprecision;
124
125 boost::random::mt19937 gen;
126 boost::uniform_int<> d(3, std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits : 3000);
127 boost::timer tim;
128
129 while (true)
130 {
131 T val(generate_random<typename component_type<T>::type>(d(gen)), generate_random<typename component_type<T>::type>(d(gen)));
132 #ifndef BOOST_NO_EXCEPTIONS
133 try
134 {
135 #endif
136 std::stringstream ss;
137 boost::archive::text_oarchive oa(ss);
138 oa << static_cast<const T&>(val);
139 boost::archive::text_iarchive ia(ss);
140 T val2;
141 ia >> val2;
142 BOOST_CHECK_EQUAL(val, val2);
143
144 ss.clear();
145 boost::archive::binary_oarchive ob(ss);
146 ob << static_cast<const T&>(val);
147 boost::archive::binary_iarchive ib(ss);
148 ib >> val2;
149 BOOST_CHECK_EQUAL(val, val2);
150 #ifndef BOOST_NO_EXCEPTIONS
151 }
152 catch (const boost::exception& e)
153 {
154 std::cout << "Caught boost::exception with:\n";
155 std::cout << diagnostic_information(e);
156 }
157 catch (const std::exception& e)
158 {
159 std::cout << "Caught std::exception with:\n";
160 std::cout << e.what() << std::endl;
161 }
162 #endif
163 test_neg(val, boost::mpl::bool_<std::numeric_limits<T>::is_signed>());
164
165 //
166 // Check to see if test is taking too long.
167 // Tests run on the compiler farm time out after 300 seconds,
168 // so don't get too close to that:
169 //
170 #ifndef CI_SUPPRESS_KNOWN_ISSUES
171 if (tim.elapsed() > 150)
172 #else
173 if (tim.elapsed() > 25)
174 #endif
175 {
176 std::cout << "Timeout reached, aborting tests now....\n";
177 break;
178 }
179 }
180 }
181
main()182 int main()
183 {
184 using namespace boost::multiprecision;
185 test<cpp_rational>();
186 return boost::report_errors();
187 }
188