1 // ratio.hpp ---------------------------------------------------------------//
3 // Copyright 2008 Howard Hinnant
4 // Copyright 2008 Beman Dawes
5 // Copyright 2009 Vicente J. Botet Escriba
7 // Distributed under the Boost Software License, Version 1.0.
8 // See http://www.boost.org/LICENSE_1_0.txt
12 This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
13 Many thanks to Howard for making his code available under the Boost license.
14 The original code was modified to conform to Boost conventions and to section
15 20.4 Compile-time rational arithmetic [ratio], of the C++ committee working
17 See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
19 time2_demo contained this comment:
21 Much thanks to Andrei Alexandrescu,
30 // The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio
32 #ifndef BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
33 #define BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
35 #include <boost/ratio/config.hpp>
36 #include <boost/ratio/detail/mpl/abs.hpp>
37 #include <boost/ratio/detail/mpl/sign.hpp>
41 #include <boost/cstdint.hpp>
42 #include <boost/type_traits/integral_constant.hpp>
43 #include <boost/core/enable_if.hpp>
44 #include <boost/integer_traits.hpp>
47 // We simply cannot include this header on gcc without getting copious warnings of the kind:
49 // boost/integer.hpp:77:30: warning: use of C99 long long integer constant
51 // And yet there is no other reasonable implementation, so we declare this a system header
52 // to suppress these warnings.
54 #if defined(__GNUC__) && (__GNUC__ >= 4)
55 #pragma GCC system_header
61 //----------------------------------------------------------------------------//
63 //----------------------------------------------------------------------------//
65 namespace ratio_detail
68 template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
71 template <boost::intmax_t X, boost::intmax_t Y>
74 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
75 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
77 BOOST_RATIO_STATIC_ASSERT(X <= max - Y , BOOST_RATIO_OVERFLOW_IN_ADD, ());
79 static const boost::intmax_t value = X + Y;
82 template <boost::intmax_t X, boost::intmax_t Y>
86 static const boost::intmax_t value = X;
89 template <boost::intmax_t X, boost::intmax_t Y>
90 class br_add<X, Y, -1>
92 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
93 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
95 BOOST_RATIO_STATIC_ASSERT(min - Y <= X, BOOST_RATIO_OVERFLOW_IN_ADD, ());
97 static const boost::intmax_t value = X + Y;
100 template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
103 template <boost::intmax_t X, boost::intmax_t Y>
104 class br_sub<X, Y, 1>
106 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
107 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
109 BOOST_RATIO_STATIC_ASSERT(min + Y <= X, BOOST_RATIO_OVERFLOW_IN_SUB, ());
111 static const boost::intmax_t value = X - Y;
114 template <boost::intmax_t X, boost::intmax_t Y>
115 class br_sub<X, Y, 0>
118 static const boost::intmax_t value = X;
121 template <boost::intmax_t X, boost::intmax_t Y>
122 class br_sub<X, Y, -1>
124 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
125 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
127 BOOST_RATIO_STATIC_ASSERT(X <= max + Y, BOOST_RATIO_OVERFLOW_IN_SUB, ());
129 static const boost::intmax_t value = X - Y;
132 template <boost::intmax_t X, boost::intmax_t Y>
135 static const boost::intmax_t nan =
136 boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
137 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
138 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
140 static const boost::intmax_t a_x = mpl::abs_c<boost::intmax_t, X>::value;
141 static const boost::intmax_t a_y = mpl::abs_c<boost::intmax_t, Y>::value;
143 BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
144 BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
145 BOOST_RATIO_STATIC_ASSERT(a_x <= max / a_y, BOOST_RATIO_OVERFLOW_IN_MUL, ());
147 static const boost::intmax_t value = X * Y;
150 template <boost::intmax_t Y>
154 static const boost::intmax_t value = 0;
157 template <boost::intmax_t X>
161 static const boost::intmax_t value = 0;
168 static const boost::intmax_t value = 0;
171 // Not actually used but left here in case needed in future maintenance
172 template <boost::intmax_t X, boost::intmax_t Y>
175 static const boost::intmax_t nan = boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
176 static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
177 static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
179 BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
180 BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
181 BOOST_RATIO_STATIC_ASSERT(Y != 0, BOOST_RATIO_DIVIDE_BY_0, ());
183 static const boost::intmax_t value = X / Y;
187 template <class R1, class R2> struct ratio_add;
188 template <class R1, class R2> struct ratio_subtract;
189 template <class R1, class R2> struct ratio_multiply;
190 template <class R1, class R2> struct ratio_divide;
192 template <class R1, class R2>
195 //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value R1::num *
196 //R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den.
197 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
199 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
200 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
202 // No need to normalize as ratio_multiply is already normalized
203 typedef typename ratio_multiply
205 ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
208 boost::ratio_detail::br_add
210 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
211 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
217 template <class R, boost::intmax_t D>
218 struct ratio_add<R, ratio<0,D> >
223 template <class R1, class R2>
224 struct ratio_subtract
226 //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value
227 // R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den.
228 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
230 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
231 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
233 // No need to normalize as ratio_multiply is already normalized
234 typedef typename ratio_multiply
236 ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
239 boost::ratio_detail::br_sub
241 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
242 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
249 template <class R, boost::intmax_t D>
250 struct ratio_subtract<R, ratio<0,D> >
255 template <class R1, class R2>
256 struct ratio_multiply
258 // The nested typedef type shall be a synonym for ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>::type.
259 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
261 static const boost::intmax_t gcd_n1_d2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::den>::value;
262 static const boost::intmax_t gcd_d1_n2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::num>::value;
264 typedef typename ratio
266 boost::ratio_detail::br_mul<R1::num / gcd_n1_d2, R2::num / gcd_d1_n2>::value,
267 boost::ratio_detail::br_mul<R2::den / gcd_n1_d2, R1::den / gcd_d1_n2>::value
271 template <class R1, class R2>
274 // The nested typedef type shall be a synonym for ratio<R1::num * R2::den, R2::num * R1::den>::type.
275 // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
277 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
278 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
280 typedef typename ratio
282 boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
283 boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
286 template <class R1, class R2>
287 struct is_evenly_divisible_by
290 static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
291 static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
293 typedef integral_constant<bool,
294 ((R2::num / gcd_n1_n2 ==1) && (R1::den / gcd_d1_d2)==1)
299 struct is_ratio : public boost::false_type
301 template <boost::intmax_t N, boost::intmax_t D>
302 struct is_ratio<ratio<N, D> > : public boost::true_type
305 template <class R1, class R2,
306 boost::intmax_t Q1 = R1::num / R1::den, boost::intmax_t M1 = R1::num % R1::den,
307 boost::intmax_t Q2 = R2::num / R2::den, boost::intmax_t M2 = R2::num % R2::den>
310 static const bool value = Q1 < Q2;
313 template <class R1, class R2, boost::intmax_t Q>
314 struct ratio_less1<R1, R2, Q, 0, Q, 0>
316 static const bool value = false;
319 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M2>
320 struct ratio_less1<R1, R2, Q, 0, Q, M2>
322 static const bool value = true;
325 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1>
326 struct ratio_less1<R1, R2, Q, M1, Q, 0>
328 static const bool value = false;
331 template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1, boost::intmax_t M2>
332 struct ratio_less1<R1, R2, Q, M1, Q, M2>
334 static const bool value = ratio_less1<ratio<R2::den, M2>, ratio<R1::den, M1>
341 boost::intmax_t S1 = mpl::sign_c<boost::intmax_t, R1::num>::value,
342 boost::intmax_t S2 = mpl::sign_c<boost::intmax_t, R2::num>::value
346 static const bool value = S1 < S2;
349 template <class R1, class R2>
350 struct ratio_less<R1, R2, 1LL, 1LL>
352 static const bool value = ratio_less1<R1, R2>::value;
355 template <class R1, class R2>
356 struct ratio_less<R1, R2, -1LL, -1LL>
358 static const bool value = ratio_less1<ratio<-R2::num, R2::den>,
359 ratio<-R1::num, R1::den> >::value;
363 } // namespace ratio_detail
367 #endif // BOOST_RATIO_HPP