Chris@16
|
1 // ratio.hpp ---------------------------------------------------------------//
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright 2008 Howard Hinnant
|
Chris@16
|
4 // Copyright 2008 Beman Dawes
|
Chris@16
|
5 // Copyright 2009 Vicente J. Botet Escriba
|
Chris@16
|
6
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
8 // See http://www.boost.org/LICENSE_1_0.txt
|
Chris@16
|
9
|
Chris@16
|
10 /*
|
Chris@16
|
11
|
Chris@16
|
12 This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
|
Chris@16
|
13 Many thanks to Howard for making his code available under the Boost license.
|
Chris@16
|
14 The original code was modified to conform to Boost conventions and to section
|
Chris@16
|
15 20.4 Compile-time rational arithmetic [ratio], of the C++ committee working
|
Chris@16
|
16 paper N2798.
|
Chris@16
|
17 See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
|
Chris@16
|
18
|
Chris@16
|
19 time2_demo contained this comment:
|
Chris@16
|
20
|
Chris@16
|
21 Much thanks to Andrei Alexandrescu,
|
Chris@16
|
22 Walter Brown,
|
Chris@16
|
23 Peter Dimov,
|
Chris@16
|
24 Jeff Garland,
|
Chris@16
|
25 Terry Golubiewski,
|
Chris@16
|
26 Daniel Krugler,
|
Chris@16
|
27 Anthony Williams.
|
Chris@16
|
28 */
|
Chris@16
|
29
|
Chris@16
|
30 // The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio
|
Chris@16
|
31
|
Chris@16
|
32 #ifndef BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
|
Chris@16
|
33 #define BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
|
Chris@16
|
34
|
Chris@16
|
35 #include <boost/ratio/config.hpp>
|
Chris@16
|
36 #include <boost/ratio/detail/mpl/abs.hpp>
|
Chris@16
|
37 #include <boost/ratio/detail/mpl/sign.hpp>
|
Chris@16
|
38 #include <cstdlib>
|
Chris@16
|
39 #include <climits>
|
Chris@16
|
40 #include <limits>
|
Chris@16
|
41 #include <boost/cstdint.hpp>
|
Chris@16
|
42 #include <boost/type_traits/integral_constant.hpp>
|
Chris@101
|
43 #include <boost/core/enable_if.hpp>
|
Chris@16
|
44 #include <boost/integer_traits.hpp>
|
Chris@16
|
45
|
Chris@16
|
46 //
|
Chris@16
|
47 // We simply cannot include this header on gcc without getting copious warnings of the kind:
|
Chris@16
|
48 //
|
Chris@16
|
49 // boost/integer.hpp:77:30: warning: use of C99 long long integer constant
|
Chris@16
|
50 //
|
Chris@16
|
51 // And yet there is no other reasonable implementation, so we declare this a system header
|
Chris@16
|
52 // to suppress these warnings.
|
Chris@16
|
53 //
|
Chris@16
|
54 #if defined(__GNUC__) && (__GNUC__ >= 4)
|
Chris@16
|
55 #pragma GCC system_header
|
Chris@16
|
56 #endif
|
Chris@16
|
57
|
Chris@16
|
58 namespace boost
|
Chris@16
|
59 {
|
Chris@16
|
60
|
Chris@16
|
61 //----------------------------------------------------------------------------//
|
Chris@16
|
62 // helpers //
|
Chris@16
|
63 //----------------------------------------------------------------------------//
|
Chris@16
|
64
|
Chris@16
|
65 namespace ratio_detail
|
Chris@16
|
66 {
|
Chris@16
|
67
|
Chris@16
|
68 template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
|
Chris@16
|
69 class br_add;
|
Chris@16
|
70
|
Chris@16
|
71 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
72 class br_add<X, Y, 1>
|
Chris@16
|
73 {
|
Chris@16
|
74 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
75 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
76
|
Chris@16
|
77 BOOST_RATIO_STATIC_ASSERT(X <= max - Y , BOOST_RATIO_OVERFLOW_IN_ADD, ());
|
Chris@16
|
78 public:
|
Chris@16
|
79 static const boost::intmax_t value = X + Y;
|
Chris@16
|
80 };
|
Chris@16
|
81
|
Chris@16
|
82 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
83 class br_add<X, Y, 0>
|
Chris@16
|
84 {
|
Chris@16
|
85 public:
|
Chris@16
|
86 static const boost::intmax_t value = X;
|
Chris@16
|
87 };
|
Chris@16
|
88
|
Chris@16
|
89 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
90 class br_add<X, Y, -1>
|
Chris@16
|
91 {
|
Chris@16
|
92 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
93 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
94
|
Chris@16
|
95 BOOST_RATIO_STATIC_ASSERT(min - Y <= X, BOOST_RATIO_OVERFLOW_IN_ADD, ());
|
Chris@16
|
96 public:
|
Chris@16
|
97 static const boost::intmax_t value = X + Y;
|
Chris@16
|
98 };
|
Chris@16
|
99
|
Chris@16
|
100 template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
|
Chris@16
|
101 class br_sub;
|
Chris@16
|
102
|
Chris@16
|
103 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
104 class br_sub<X, Y, 1>
|
Chris@16
|
105 {
|
Chris@16
|
106 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
107 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
108
|
Chris@16
|
109 BOOST_RATIO_STATIC_ASSERT(min + Y <= X, BOOST_RATIO_OVERFLOW_IN_SUB, ());
|
Chris@16
|
110 public:
|
Chris@16
|
111 static const boost::intmax_t value = X - Y;
|
Chris@16
|
112 };
|
Chris@16
|
113
|
Chris@16
|
114 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
115 class br_sub<X, Y, 0>
|
Chris@16
|
116 {
|
Chris@16
|
117 public:
|
Chris@16
|
118 static const boost::intmax_t value = X;
|
Chris@16
|
119 };
|
Chris@16
|
120
|
Chris@16
|
121 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
122 class br_sub<X, Y, -1>
|
Chris@16
|
123 {
|
Chris@16
|
124 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
125 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
126
|
Chris@16
|
127 BOOST_RATIO_STATIC_ASSERT(X <= max + Y, BOOST_RATIO_OVERFLOW_IN_SUB, ());
|
Chris@16
|
128 public:
|
Chris@16
|
129 static const boost::intmax_t value = X - Y;
|
Chris@16
|
130 };
|
Chris@16
|
131
|
Chris@16
|
132 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
133 class br_mul
|
Chris@16
|
134 {
|
Chris@16
|
135 static const boost::intmax_t nan =
|
Chris@16
|
136 boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
|
Chris@16
|
137 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
138 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
139
|
Chris@16
|
140 static const boost::intmax_t a_x = mpl::abs_c<boost::intmax_t, X>::value;
|
Chris@16
|
141 static const boost::intmax_t a_y = mpl::abs_c<boost::intmax_t, Y>::value;
|
Chris@16
|
142
|
Chris@16
|
143 BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
|
Chris@16
|
144 BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
|
Chris@16
|
145 BOOST_RATIO_STATIC_ASSERT(a_x <= max / a_y, BOOST_RATIO_OVERFLOW_IN_MUL, ());
|
Chris@16
|
146 public:
|
Chris@16
|
147 static const boost::intmax_t value = X * Y;
|
Chris@16
|
148 };
|
Chris@16
|
149
|
Chris@16
|
150 template <boost::intmax_t Y>
|
Chris@16
|
151 class br_mul<0, Y>
|
Chris@16
|
152 {
|
Chris@16
|
153 public:
|
Chris@16
|
154 static const boost::intmax_t value = 0;
|
Chris@16
|
155 };
|
Chris@16
|
156
|
Chris@16
|
157 template <boost::intmax_t X>
|
Chris@16
|
158 class br_mul<X, 0>
|
Chris@16
|
159 {
|
Chris@16
|
160 public:
|
Chris@16
|
161 static const boost::intmax_t value = 0;
|
Chris@16
|
162 };
|
Chris@16
|
163
|
Chris@16
|
164 template <>
|
Chris@16
|
165 class br_mul<0, 0>
|
Chris@16
|
166 {
|
Chris@16
|
167 public:
|
Chris@16
|
168 static const boost::intmax_t value = 0;
|
Chris@16
|
169 };
|
Chris@16
|
170
|
Chris@16
|
171 // Not actually used but left here in case needed in future maintenance
|
Chris@16
|
172 template <boost::intmax_t X, boost::intmax_t Y>
|
Chris@16
|
173 class br_div
|
Chris@16
|
174 {
|
Chris@16
|
175 static const boost::intmax_t nan = boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
|
Chris@16
|
176 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
|
Chris@16
|
177 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
|
Chris@16
|
178
|
Chris@16
|
179 BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
|
Chris@16
|
180 BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
|
Chris@16
|
181 BOOST_RATIO_STATIC_ASSERT(Y != 0, BOOST_RATIO_DIVIDE_BY_0, ());
|
Chris@16
|
182 public:
|
Chris@16
|
183 static const boost::intmax_t value = X / Y;
|
Chris@16
|
184 };
|
Chris@16
|
185
|
Chris@16
|
186 // ratio arithmetic
|
Chris@16
|
187 template <class R1, class R2> struct ratio_add;
|
Chris@16
|
188 template <class R1, class R2> struct ratio_subtract;
|
Chris@16
|
189 template <class R1, class R2> struct ratio_multiply;
|
Chris@16
|
190 template <class R1, class R2> struct ratio_divide;
|
Chris@16
|
191
|
Chris@16
|
192 template <class R1, class R2>
|
Chris@16
|
193 struct ratio_add
|
Chris@16
|
194 {
|
Chris@16
|
195 //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value R1::num *
|
Chris@16
|
196 //R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den.
|
Chris@16
|
197 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
|
Chris@16
|
198 private:
|
Chris@16
|
199 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
|
Chris@16
|
200 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
|
Chris@16
|
201 public:
|
Chris@16
|
202 // No need to normalize as ratio_multiply is already normalized
|
Chris@16
|
203 typedef typename ratio_multiply
|
Chris@16
|
204 <
|
Chris@16
|
205 ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
|
Chris@16
|
206 ratio
|
Chris@16
|
207 <
|
Chris@16
|
208 boost::ratio_detail::br_add
|
Chris@16
|
209 <
|
Chris@16
|
210 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
|
Chris@16
|
211 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
|
Chris@16
|
212 >::value,
|
Chris@16
|
213 R2::den
|
Chris@16
|
214 >
|
Chris@16
|
215 >::type type;
|
Chris@16
|
216 };
|
Chris@16
|
217 template <class R, boost::intmax_t D>
|
Chris@16
|
218 struct ratio_add<R, ratio<0,D> >
|
Chris@16
|
219 {
|
Chris@16
|
220 typedef R type;
|
Chris@16
|
221 };
|
Chris@16
|
222
|
Chris@16
|
223 template <class R1, class R2>
|
Chris@16
|
224 struct ratio_subtract
|
Chris@16
|
225 {
|
Chris@16
|
226 //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value
|
Chris@16
|
227 // R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den.
|
Chris@16
|
228 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
|
Chris@16
|
229 private:
|
Chris@16
|
230 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
|
Chris@16
|
231 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
|
Chris@16
|
232 public:
|
Chris@16
|
233 // No need to normalize as ratio_multiply is already normalized
|
Chris@16
|
234 typedef typename ratio_multiply
|
Chris@16
|
235 <
|
Chris@16
|
236 ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
|
Chris@16
|
237 ratio
|
Chris@16
|
238 <
|
Chris@16
|
239 boost::ratio_detail::br_sub
|
Chris@16
|
240 <
|
Chris@16
|
241 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
|
Chris@16
|
242 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
|
Chris@16
|
243 >::value,
|
Chris@16
|
244 R2::den
|
Chris@16
|
245 >
|
Chris@16
|
246 >::type type;
|
Chris@16
|
247 };
|
Chris@16
|
248
|
Chris@16
|
249 template <class R, boost::intmax_t D>
|
Chris@16
|
250 struct ratio_subtract<R, ratio<0,D> >
|
Chris@16
|
251 {
|
Chris@16
|
252 typedef R type;
|
Chris@16
|
253 };
|
Chris@16
|
254
|
Chris@16
|
255 template <class R1, class R2>
|
Chris@16
|
256 struct ratio_multiply
|
Chris@16
|
257 {
|
Chris@16
|
258 // The nested typedef type shall be a synonym for ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>::type.
|
Chris@16
|
259 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
|
Chris@16
|
260 private:
|
Chris@16
|
261 static const boost::intmax_t gcd_n1_d2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::den>::value;
|
Chris@16
|
262 static const boost::intmax_t gcd_d1_n2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::num>::value;
|
Chris@16
|
263 public:
|
Chris@16
|
264 typedef typename ratio
|
Chris@16
|
265 <
|
Chris@16
|
266 boost::ratio_detail::br_mul<R1::num / gcd_n1_d2, R2::num / gcd_d1_n2>::value,
|
Chris@16
|
267 boost::ratio_detail::br_mul<R2::den / gcd_n1_d2, R1::den / gcd_d1_n2>::value
|
Chris@16
|
268 >::type type;
|
Chris@16
|
269 };
|
Chris@16
|
270
|
Chris@16
|
271 template <class R1, class R2>
|
Chris@16
|
272 struct ratio_divide
|
Chris@16
|
273 {
|
Chris@16
|
274 // The nested typedef type shall be a synonym for ratio<R1::num * R2::den, R2::num * R1::den>::type.
|
Chris@16
|
275 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
|
Chris@16
|
276 private:
|
Chris@16
|
277 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
|
Chris@16
|
278 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
|
Chris@16
|
279 public:
|
Chris@16
|
280 typedef typename ratio
|
Chris@16
|
281 <
|
Chris@16
|
282 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
|
Chris@16
|
283 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
|
Chris@16
|
284 >::type type;
|
Chris@16
|
285 };
|
Chris@16
|
286 template <class R1, class R2>
|
Chris@16
|
287 struct is_evenly_divisible_by
|
Chris@16
|
288 {
|
Chris@16
|
289 private:
|
Chris@16
|
290 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
|
Chris@16
|
291 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
|
Chris@16
|
292 public:
|
Chris@16
|
293 typedef integral_constant<bool,
|
Chris@16
|
294 ((R2::num / gcd_n1_n2 ==1) && (R1::den / gcd_d1_d2)==1)
|
Chris@16
|
295 > type;
|
Chris@16
|
296 };
|
Chris@16
|
297
|
Chris@16
|
298 template <class T>
|
Chris@16
|
299 struct is_ratio : public boost::false_type
|
Chris@16
|
300 {};
|
Chris@16
|
301 template <boost::intmax_t N, boost::intmax_t D>
|
Chris@16
|
302 struct is_ratio<ratio<N, D> > : public boost::true_type
|
Chris@16
|
303 {};
|
Chris@16
|
304
|
Chris@16
|
305 template <class R1, class R2,
|
Chris@16
|
306 boost::intmax_t Q1 = R1::num / R1::den, boost::intmax_t M1 = R1::num % R1::den,
|
Chris@16
|
307 boost::intmax_t Q2 = R2::num / R2::den, boost::intmax_t M2 = R2::num % R2::den>
|
Chris@16
|
308 struct ratio_less1
|
Chris@16
|
309 {
|
Chris@16
|
310 static const bool value = Q1 < Q2;
|
Chris@16
|
311 };
|
Chris@16
|
312
|
Chris@16
|
313 template <class R1, class R2, boost::intmax_t Q>
|
Chris@16
|
314 struct ratio_less1<R1, R2, Q, 0, Q, 0>
|
Chris@16
|
315 {
|
Chris@16
|
316 static const bool value = false;
|
Chris@16
|
317 };
|
Chris@16
|
318
|
Chris@16
|
319 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M2>
|
Chris@16
|
320 struct ratio_less1<R1, R2, Q, 0, Q, M2>
|
Chris@16
|
321 {
|
Chris@16
|
322 static const bool value = true;
|
Chris@16
|
323 };
|
Chris@16
|
324
|
Chris@16
|
325 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1>
|
Chris@16
|
326 struct ratio_less1<R1, R2, Q, M1, Q, 0>
|
Chris@16
|
327 {
|
Chris@16
|
328 static const bool value = false;
|
Chris@16
|
329 };
|
Chris@16
|
330
|
Chris@16
|
331 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1, boost::intmax_t M2>
|
Chris@16
|
332 struct ratio_less1<R1, R2, Q, M1, Q, M2>
|
Chris@16
|
333 {
|
Chris@16
|
334 static const bool value = ratio_less1<ratio<R2::den, M2>, ratio<R1::den, M1>
|
Chris@16
|
335 >::value;
|
Chris@16
|
336 };
|
Chris@16
|
337
|
Chris@16
|
338 template <
|
Chris@16
|
339 class R1,
|
Chris@16
|
340 class R2,
|
Chris@16
|
341 boost::intmax_t S1 = mpl::sign_c<boost::intmax_t, R1::num>::value,
|
Chris@16
|
342 boost::intmax_t S2 = mpl::sign_c<boost::intmax_t, R2::num>::value
|
Chris@16
|
343 >
|
Chris@16
|
344 struct ratio_less
|
Chris@16
|
345 {
|
Chris@16
|
346 static const bool value = S1 < S2;
|
Chris@16
|
347 };
|
Chris@16
|
348
|
Chris@16
|
349 template <class R1, class R2>
|
Chris@16
|
350 struct ratio_less<R1, R2, 1LL, 1LL>
|
Chris@16
|
351 {
|
Chris@16
|
352 static const bool value = ratio_less1<R1, R2>::value;
|
Chris@16
|
353 };
|
Chris@16
|
354
|
Chris@16
|
355 template <class R1, class R2>
|
Chris@16
|
356 struct ratio_less<R1, R2, -1LL, -1LL>
|
Chris@16
|
357 {
|
Chris@16
|
358 static const bool value = ratio_less1<ratio<-R2::num, R2::den>,
|
Chris@16
|
359 ratio<-R1::num, R1::den> >::value;
|
Chris@16
|
360 };
|
Chris@16
|
361
|
Chris@16
|
362
|
Chris@16
|
363 } // namespace ratio_detail
|
Chris@16
|
364
|
Chris@16
|
365 } // namespace boost
|
Chris@16
|
366
|
Chris@16
|
367 #endif // BOOST_RATIO_HPP
|