1 //  ratio.hpp  ---------------------------------------------------------------//
2 
3 //  Copyright 2008 Howard Hinnant
4 //  Copyright 2008 Beman Dawes
5 //  Copyright 2009 Vicente J. Botet Escriba
6 
7 //  Distributed under the Boost Software License, Version 1.0.
8 //  See http://www.boost.org/LICENSE_1_0.txt
9 
10 /*
11 
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
16 paper N2798.
17 See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
18 
19 time2_demo contained this comment:
20 
21     Much thanks to Andrei Alexandrescu,
22                    Walter Brown,
23                    Peter Dimov,
24                    Jeff Garland,
25                    Terry Golubiewski,
26                    Daniel Krugler,
27                    Anthony Williams.
28 */
29 
30 // The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio
31 
32 #ifndef BOOST_RATIO_RATIO_HPP
33 #define BOOST_RATIO_RATIO_HPP
34 
35 #include <boost/ratio/config.hpp>
36 #include <boost/ratio/detail/mpl/abs.hpp>
37 #include <boost/ratio/detail/mpl/sign.hpp>
38 #include <boost/ratio/detail/mpl/gcd.hpp>
39 #include <boost/ratio/detail/mpl/lcm.hpp>
40 #include <cstdlib>
41 #include <climits>
42 #include <limits>
43 #include <boost/cstdint.hpp>
44 #include <boost/type_traits/integral_constant.hpp>
45 #include <boost/core/enable_if.hpp>
46 #include <boost/integer_traits.hpp>
47 #include <boost/ratio/ratio_fwd.hpp>
48 #include <boost/ratio/detail/overflow_helpers.hpp>
49 #ifdef BOOST_RATIO_EXTENSIONS
50 #include <boost/rational.hpp>
51 #include <boost/ratio/mpl/rational_c_tag.hpp>
52 #endif
53 
54 //
55 // We simply cannot include this header on gcc without getting copious warnings of the kind:
56 //
57 // boost/integer.hpp:77:30: warning: use of C99 long long integer constant
58 //
59 // And yet there is no other reasonable implementation, so we declare this a system header
60 // to suppress these warnings.
61 //
62 #if defined(__GNUC__) && (__GNUC__ >= 4)
63 #pragma GCC system_header
64 #endif
65 
66 namespace boost
67 {
68 
69 
70 //----------------------------------------------------------------------------//
71 //                                                                            //
72 //                20.6.1 Class template ratio [ratio.ratio]                   //
73 //                                                                            //
74 //----------------------------------------------------------------------------//
75 
76 template <boost::intmax_t N, boost::intmax_t D>
77 class ratio
78 {
79     static const boost::intmax_t ABS_N = mpl::abs_c<boost::intmax_t, N>::value;
80     static const boost::intmax_t ABS_D = mpl::abs_c<boost::intmax_t, D>::value;
81     BOOST_RATIO_STATIC_ASSERT(ABS_N >= 0, BOOST_RATIO_NUMERATOR_IS_OUT_OF_RANGE, ());
82     BOOST_RATIO_STATIC_ASSERT(ABS_D > 0, BOOST_RATIO_DENOMINATOR_IS_OUT_OF_RANGE, ());
83     BOOST_RATIO_STATIC_ASSERT(D != 0, BOOST_RATIO_DIVIDE_BY_0 , ());
84     static const boost::intmax_t SIGN_N = mpl::sign_c<boost::intmax_t,N>::value
85       * mpl::sign_c<boost::intmax_t,D>::value;
86     static const boost::intmax_t GCD = mpl::gcd_c<boost::intmax_t, ABS_N, ABS_D>::value;
87 public:
88     BOOST_STATIC_CONSTEXPR boost::intmax_t num = SIGN_N * ABS_N / GCD;
89     BOOST_STATIC_CONSTEXPR boost::intmax_t den = ABS_D / GCD;
90 
91 #ifdef BOOST_RATIO_EXTENSIONS
92     typedef mpl::rational_c_tag tag;
93     typedef boost::rational<boost::intmax_t> value_type;
94     typedef boost::intmax_t num_type;
95     typedef boost::intmax_t den_type;
ratio()96     ratio()
97     {}
98     template <boost::intmax_t _N2, boost::intmax_t _D2>
ratio(const ratio<_N2,_D2> &,typename enable_if_c<(ratio<_N2,_D2>::num==num && ratio<_N2,_D2>::den==den)>::type * =0)99     ratio(const ratio<_N2, _D2>&,
100         typename enable_if_c
101             <
102                 (ratio<_N2, _D2>::num == num &&
103                 ratio<_N2, _D2>::den == den)
104             >::type* = 0)
105     {}
106 
107     template <boost::intmax_t _N2, boost::intmax_t _D2>
108         typename enable_if_c
109         <
110             (ratio<_N2, _D2>::num == num &&
111             ratio<_N2, _D2>::den == den),
112             ratio&
113         >::type
operator =(const ratio<_N2,_D2> &)114     operator=(const ratio<_N2, _D2>&) {return *this;}
115 
value()116     static value_type value() {return value_type(num,den);}
operator ()() const117     value_type operator()() const {return value();}
118 #endif
119     typedef ratio<num, den> type;
120 };
121 
122 #if defined(BOOST_NO_CXX11_CONSTEXPR)
123 template <boost::intmax_t N, boost::intmax_t D>
124 const    boost::intmax_t ratio<N, D>::num;
125 template <boost::intmax_t N, boost::intmax_t D>
126 const    boost::intmax_t ratio<N, D>::den;
127 #endif
128 
129 //----------------------------------------------------------------------------//
130 //                                                                            //
131 //                20.6.2 Arithmetic on ratio types [ratio.arithmetic]         //
132 //                                                                            //
133 //----------------------------------------------------------------------------//
134 
135 template <class R1, class R2>
136 struct ratio_add
137 : boost::ratio_detail::ratio_add<R1, R2>::type
138 {
139 };
140 
141 template <class R1, class R2>
142 struct ratio_subtract
143 : boost::ratio_detail::ratio_subtract<R1, R2>::type
144 {
145 };
146 
147 template <class R1, class R2>
148 struct ratio_multiply
149 : boost::ratio_detail::ratio_multiply<R1, R2>::type
150 {
151 };
152 
153 template <class R1, class R2>
154 struct ratio_divide
155 : boost::ratio_detail::ratio_divide<R1, R2>::type
156 {
157 };
158 
159 //----------------------------------------------------------------------------//
160 //                                                                            //
161 //                20.6.3 Comparision of ratio types [ratio.comparison]        //
162 //                                                                            //
163 //----------------------------------------------------------------------------//
164 
165 // ratio_equal
166 
167 template <class R1, class R2>
168 struct ratio_equal
169     : public boost::integral_constant<bool,
170                                (R1::num == R2::num && R1::den == R2::den)>
171 {};
172 
173 template <class R1, class R2>
174 struct ratio_not_equal
175     : public boost::integral_constant<bool, !ratio_equal<R1, R2>::value>
176 {};
177 
178 // ratio_less
179 
180 template <class R1, class R2>
181 struct ratio_less
182     : boost::integral_constant<bool, boost::ratio_detail::ratio_less<R1, R2>::value>
183 {};
184 
185 template <class R1, class R2>
186 struct ratio_less_equal
187     : boost::integral_constant<bool, !ratio_less<R2, R1>::value>
188 {};
189 
190 template <class R1, class R2>
191 struct ratio_greater
192     : boost::integral_constant<bool, ratio_less<R2, R1>::value>
193 {};
194 
195 template <class R1, class R2>
196 struct ratio_greater_equal
197     : boost::integral_constant<bool, !ratio_less<R1, R2>::value>
198 {};
199 
200 template <class R1, class R2>
201 struct ratio_gcd :
202     ratio<mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value,
203         mpl::lcm_c<boost::intmax_t, R1::den, R2::den>::value>::type
204 {
205 };
206 
207     //----------------------------------------------------------------------------//
208     //                                                                            //
209     //                More arithmetic on ratio types [ratio.arithmetic]           //
210     //                                                                            //
211     //----------------------------------------------------------------------------//
212 
213 #ifdef BOOST_RATIO_EXTENSIONS
214 template <class R>
215 struct ratio_negate
216     : ratio<-R::num, R::den>::type
217 {
218 };
219 template <class R>
220 struct ratio_abs
221     : ratio<mpl::abs_c<boost::intmax_t, R::num>::value, R::den>::type
222 {
223 };
224 template <class R>
225 struct ratio_sign
226     : mpl::sign_c<boost::intmax_t, R::num>
227 {
228 };
229 
230 template <class R>
231 struct ratio_inverse
232     : ratio<R::den, R::num>::type
233 {
234 };
235 
236 
237 template <class R1, class R2>
238 struct ratio_lcm :
239     ratio<mpl::lcm_c<boost::intmax_t, R1::num, R2::num>::value,
240         mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value>::type
241 {
242 };
243 
244 template <class R1, class R2>
245 struct ratio_modulo :
246     ratio<(R1::num * R2::den) % (R2::num * R1::den), R1::den * R2::den>::type
247 {
248 };
249 
250 namespace detail {
251   template <class R1, class R2, bool r1ltr2>
252   struct ratio_min : R1 {};
253   template <class R1, class R2>
254   struct ratio_min<R1,R2,false> : R2 {};
255 
256   template <class R1, class R2, bool r1ltr2>
257   struct ratio_max : R2 {};
258   template <class R1, class R2>
259   struct ratio_max<R1,R2,false> : R1 {};
260 }
261 
262 template <class R1, class R2>
263 struct ratio_min : detail::ratio_min<R1, R2, ratio_less<R1,R2>::value>::type
264 {
265 };
266 
267 template <class R1, class R2>
268 struct ratio_max : detail::ratio_max<R1, R2, ratio_less<R1,R2>::value>::type
269 {
270 };
271 
272 template<typename R, int p>
273 struct ratio_power :
274   ratio_multiply<
275     typename ratio_power<R, p%2>::type,
276     typename ratio_power<typename ratio_multiply<R, R>::type, p/2>::type
277   >::type
278 {};
279 
280 template<typename R>
281 struct ratio_power<R, 0> : ratio<1>::type {};
282 
283 template<typename R>
284 struct ratio_power<R, 1> : R {};
285 
286 template<typename R>
287 struct ratio_power<R, -1> : ratio_divide<ratio<1>, R>::type {};
288 
289 #endif
290 }  // namespace boost
291 
292 
293 #endif  // BOOST_RATIO_RATIO_HPP
294