]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/multiprecision/include/boost/multiprecision/rational_adaptor.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / multiprecision / include / boost / multiprecision / rational_adaptor.hpp
1 ///////////////////////////////////////////////////////////////
2 // Copyright 2011 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5
6 #ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP
7 #define BOOST_MATH_RATIONAL_ADAPTER_HPP
8
9 #include <iostream>
10 #include <iomanip>
11 #include <sstream>
12 #include <boost/cstdint.hpp>
13 #include <boost/functional/hash_fwd.hpp>
14 #include <boost/multiprecision/number.hpp>
15 #ifdef BOOST_MSVC
16 # pragma warning(push)
17 # pragma warning(disable:4512 4127)
18 #endif
19 #include <boost/rational.hpp>
20 #ifdef BOOST_MSVC
21 # pragma warning(pop)
22 #endif
23
24 namespace boost{
25 namespace multiprecision{
26 namespace backends{
27
28 template <class IntBackend>
29 struct rational_adaptor
30 {
31 typedef number<IntBackend> integer_type;
32 typedef boost::rational<integer_type> rational_type;
33
34 typedef typename IntBackend::signed_types signed_types;
35 typedef typename IntBackend::unsigned_types unsigned_types;
36 typedef typename IntBackend::float_types float_types;
37
38 rational_adaptor() BOOST_MP_NOEXCEPT_IF(noexcept(rational_type())) {}
39 rational_adaptor(const rational_adaptor& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<const rational_type&>()))
40 {
41 m_value = o.m_value;
42 }
43 rational_adaptor(const IntBackend& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<const IntBackend&>()))) : m_value(o) {}
44
45 template <class U>
46 rational_adaptor(const U& u, typename enable_if_c<is_convertible<U, IntBackend>::value>::type* = 0)
47 : m_value(static_cast<integer_type>(u)){}
48 template <class U>
49 explicit rational_adaptor(const U& u,
50 typename enable_if_c<
51 boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_convertible<U, IntBackend>::value
52 >::type* = 0)
53 : m_value(IntBackend(u)){}
54 template <class U>
55 typename enable_if_c<(boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_arithmetic<U>::value), rational_adaptor&>::type operator = (const U& u)
56 {
57 m_value = IntBackend(u);
58 return *this;
59 }
60
61 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
62 rational_adaptor(rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<rational_type>()))) : m_value(static_cast<rational_type&&>(o.m_value)) {}
63 rational_adaptor(IntBackend&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<IntBackend>()))) : m_value(static_cast<IntBackend&&>(o)) {}
64 rational_adaptor& operator = (rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<rational_type>()))
65 {
66 m_value = static_cast<rational_type&&>(o.m_value);
67 return *this;
68 }
69 #endif
70 rational_adaptor& operator = (const rational_adaptor& o)
71 {
72 m_value = o.m_value;
73 return *this;
74 }
75 rational_adaptor& operator = (const IntBackend& o)
76 {
77 m_value = o;
78 return *this;
79 }
80 template <class Int>
81 typename enable_if<is_integral<Int>, rational_adaptor&>::type operator = (Int i)
82 {
83 m_value = i;
84 return *this;
85 }
86 template <class Float>
87 typename enable_if<is_floating_point<Float>, rational_adaptor&>::type operator = (Float i)
88 {
89 int e;
90 Float f = std::frexp(i, &e);
91 f = std::ldexp(f, std::numeric_limits<Float>::digits);
92 e -= std::numeric_limits<Float>::digits;
93 integer_type num(f);
94 integer_type denom(1u);
95 if(e > 0)
96 {
97 num <<= e;
98 }
99 else if(e < 0)
100 {
101 denom <<= -e;
102 }
103 m_value.assign(num, denom);
104 return *this;
105 }
106 rational_adaptor& operator = (const char* s)
107 {
108 std::string s1;
109 multiprecision::number<IntBackend> v1, v2;
110 char c;
111 bool have_hex = false;
112 const char* p = s; // saved for later
113
114 while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
115 {
116 if(c == 'x' || c == 'X')
117 have_hex = true;
118 s1.append(1, c);
119 ++s;
120 }
121 v1.assign(s1);
122 s1.erase();
123 if(c == '/')
124 {
125 ++s;
126 while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
127 {
128 if(c == 'x' || c == 'X')
129 have_hex = true;
130 s1.append(1, c);
131 ++s;
132 }
133 v2.assign(s1);
134 }
135 else
136 v2 = 1;
137 if(*s)
138 {
139 BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Could not parse the string \"") + p + std::string("\" as a valid rational number.")));
140 }
141 data().assign(v1, v2);
142 return *this;
143 }
144 void swap(rational_adaptor& o)
145 {
146 std::swap(m_value, o.m_value);
147 }
148 std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
149 {
150 //
151 // We format the string ourselves so we can match what GMP's mpq type does:
152 //
153 std::string result = data().numerator().str(digits, f);
154 if(data().denominator() != 1)
155 {
156 result.append(1, '/');
157 result.append(data().denominator().str(digits, f));
158 }
159 return result;
160 }
161 void negate()
162 {
163 m_value = -m_value;
164 }
165 int compare(const rational_adaptor& o)const
166 {
167 return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
168 }
169 template <class Arithmatic>
170 typename enable_if_c<is_arithmetic<Arithmatic>::value && !is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
171 {
172 return m_value > i ? 1 : (m_value < i ? -1 : 0);
173 }
174 template <class Arithmatic>
175 typename enable_if_c<is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
176 {
177 rational_adaptor r;
178 r = i;
179 return this->compare(r);
180 }
181 rational_type& data() { return m_value; }
182 const rational_type& data()const { return m_value; }
183
184 template <class Archive>
185 void serialize(Archive& ar, const mpl::true_&)
186 {
187 // Saving
188 integer_type n(m_value.numerator()), d(m_value.denominator());
189 ar & n;
190 ar & d;
191 }
192 template <class Archive>
193 void serialize(Archive& ar, const mpl::false_&)
194 {
195 // Loading
196 integer_type n, d;
197 ar & n;
198 ar & d;
199 m_value.assign(n, d);
200 }
201 template <class Archive>
202 void serialize(Archive& ar, const unsigned int /*version*/)
203 {
204 typedef typename Archive::is_saving tag;
205 serialize(ar, tag());
206 }
207 private:
208 rational_type m_value;
209 };
210
211 template <class IntBackend>
212 inline void eval_add(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
213 {
214 result.data() += o.data();
215 }
216 template <class IntBackend>
217 inline void eval_subtract(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
218 {
219 result.data() -= o.data();
220 }
221 template <class IntBackend>
222 inline void eval_multiply(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
223 {
224 result.data() *= o.data();
225 }
226 template <class IntBackend>
227 inline void eval_divide(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
228 {
229 using default_ops::eval_is_zero;
230 if(eval_is_zero(o))
231 {
232 BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero."));
233 }
234 result.data() /= o.data();
235 }
236
237 template <class R, class IntBackend>
238 inline typename enable_if_c<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
239 {
240 //
241 // The generic conversion is as good as anything we can write here:
242 //
243 ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
244 }
245
246 template <class R, class IntBackend>
247 inline typename enable_if_c<(number_category<R>::value != number_kind_integer) && (number_category<R>::value != number_kind_floating_point)>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
248 {
249 typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
250 comp_t num(backend.data().numerator());
251 comp_t denom(backend.data().denominator());
252 *result = num.template convert_to<R>();
253 *result /= denom.template convert_to<R>();
254 }
255
256 template <class R, class IntBackend>
257 inline typename enable_if_c<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
258 {
259 typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
260 comp_t t = backend.data().numerator();
261 t /= backend.data().denominator();
262 *result = t.template convert_to<R>();
263 }
264
265 template <class IntBackend>
266 inline bool eval_is_zero(const rational_adaptor<IntBackend>& val)
267 {
268 return eval_is_zero(val.data().numerator().backend());
269 }
270 template <class IntBackend>
271 inline int eval_get_sign(const rational_adaptor<IntBackend>& val)
272 {
273 return eval_get_sign(val.data().numerator().backend());
274 }
275
276 template<class IntBackend, class V>
277 inline void assign_components(rational_adaptor<IntBackend>& result, const V& v1, const V& v2)
278 {
279 result.data().assign(v1, v2);
280 }
281
282 template <class IntBackend>
283 inline std::size_t hash_value(const rational_adaptor<IntBackend>& val)
284 {
285 std::size_t result = hash_value(val.data().numerator());
286 boost::hash_combine(result, val.data().denominator());
287 return result;
288 }
289
290
291 } // namespace backends
292
293 template<class IntBackend>
294 struct expression_template_default<backends::rational_adaptor<IntBackend> > : public expression_template_default<IntBackend> {};
295
296 template<class IntBackend>
297 struct number_category<backends::rational_adaptor<IntBackend> > : public mpl::int_<number_kind_rational>{};
298
299 using boost::multiprecision::backends::rational_adaptor;
300
301 template <class T>
302 struct component_type<rational_adaptor<T> >
303 {
304 typedef number<T> type;
305 };
306
307 template <class IntBackend, expression_template_option ET>
308 inline number<IntBackend, ET> numerator(const number<rational_adaptor<IntBackend>, ET>& val)
309 {
310 return val.backend().data().numerator();
311 }
312 template <class IntBackend, expression_template_option ET>
313 inline number<IntBackend, ET> denominator(const number<rational_adaptor<IntBackend>, ET>& val)
314 {
315 return val.backend().data().denominator();
316 }
317
318 #ifdef BOOST_NO_SFINAE_EXPR
319
320 namespace detail{
321
322 template<class U, class IntBackend>
323 struct is_explicitly_convertible<U, rational_adaptor<IntBackend> > : public is_explicitly_convertible<U, IntBackend> {};
324
325 }
326
327 #endif
328
329 }} // namespaces
330
331
332 namespace std{
333
334 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
335 class numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> > : public std::numeric_limits<boost::multiprecision::number<IntBackend, ExpressionTemplates> >
336 {
337 typedef std::numeric_limits<boost::multiprecision::number<IntBackend> > base_type;
338 typedef boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend> > number_type;
339 public:
340 BOOST_STATIC_CONSTEXPR bool is_integer = false;
341 BOOST_STATIC_CONSTEXPR bool is_exact = true;
342 BOOST_STATIC_CONSTEXPR number_type (min)() { return (base_type::min)(); }
343 BOOST_STATIC_CONSTEXPR number_type (max)() { return (base_type::max)(); }
344 BOOST_STATIC_CONSTEXPR number_type lowest() { return -(max)(); }
345 BOOST_STATIC_CONSTEXPR number_type epsilon() { return base_type::epsilon(); }
346 BOOST_STATIC_CONSTEXPR number_type round_error() { return epsilon() / 2; }
347 BOOST_STATIC_CONSTEXPR number_type infinity() { return base_type::infinity(); }
348 BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return base_type::quiet_NaN(); }
349 BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return base_type::signaling_NaN(); }
350 BOOST_STATIC_CONSTEXPR number_type denorm_min() { return base_type::denorm_min(); }
351 };
352
353 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
354
355 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
356 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_integer;
357 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
358 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_exact;
359
360 #endif
361
362
363 }
364
365 #endif