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/utility/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