1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
2 // unit/quantity manipulation and conversion
3 //
4 // Copyright (C) 2003-2008 Matthias Christian Schabel
5 // Copyright (C) 2008 Steven Watanabe
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #ifndef BOOST_UNITS_STATIC_RATIONAL_HPP
12 #define BOOST_UNITS_STATIC_RATIONAL_HPP
13 
14 #include <boost/integer/common_factor_ct.hpp>
15 #include <boost/mpl/less.hpp>
16 #include <boost/mpl/arithmetic.hpp>
17 
18 #ifdef __BORLANDC__
19 #include <boost/mpl/eval_if.hpp>
20 #include <boost/mpl/integral_c.hpp>
21 #include <boost/mpl/identity.hpp>
22 #endif
23 
24 #include <boost/units/config.hpp>
25 #include <boost/units/operators.hpp>
26 
27 /// \file
28 /// \brief Compile-time rational numbers and operators.
29 
30 namespace boost {
31 
32 namespace units {
33 
34 namespace detail {
35 
36 struct static_rational_tag {};
37 
38 }
39 
40 typedef long   integer_type;
41 
42 /// Compile time absolute value.
43 template<integer_type Value>
44 struct static_abs
45 {
46     BOOST_STATIC_CONSTANT(integer_type,value = Value < 0 ? -Value : Value);
47 };
48 
49 // Compile time rational number.
50 /**
51 This is an implementation of a compile time rational number, where @c static_rational<N,D> represents
52 a rational number with numerator @c N and denominator @c D. Because of the potential for ambiguity arising
53 from multiple equivalent values of @c static_rational (e.g. @c static_rational<6,2>==static_rational<3>),
54 static rationals should always be accessed through @c static_rational<N,D>::type. Template specialization
55 prevents instantiation of zero denominators (i.e. @c static_rational<N,0>). The following compile-time
56 arithmetic operators are provided for static_rational variables only (no operators are defined between
57 long and static_rational):
58     - @c mpl::negate
59     - @c mpl::plus
60     - @c mpl::minus
61     - @c mpl::times
62     - @c mpl::divides
63 
64 Neither @c static_power nor @c static_root are defined for @c static_rational. This is because template types
65 may not be floating point values, while powers and roots of rational numbers can produce floating point
66 values.
67 */
68 #ifdef __BORLANDC__
69 
70 template<integer_type X>
71 struct make_integral_c {
72     typedef boost::mpl::integral_c<integer_type, X> type;
73 };
74 
75 template<integer_type N,integer_type D = 1>
76 class static_rational
77 {
78     public:
79 
80         typedef static_rational this_type;
81 
82         typedef boost::mpl::integral_c<integer_type, N> N_type;
83         typedef boost::mpl::integral_c<integer_type, D> D_type;
84 
85         typedef typename make_integral_c<
86             (::boost::integer::static_gcd<
87                 ::boost::units::static_abs<N>::value,
88                 ::boost::units::static_abs<D>::value
89             >::value)>::type gcd_type;
90         typedef typename boost::mpl::eval_if<
91             boost::mpl::less<
92                 D_type,
93                 boost::mpl::integral_c<integer_type, 0>
94             >,
95             boost::mpl::negate<gcd_type>,
96             gcd_type
97         >::type den_type;
98 
99     public:
100         // for mpl arithmetic support
101         typedef detail::static_rational_tag tag;
102 
103         BOOST_STATIC_CONSTANT(integer_type, Numerator =
104             (::boost::mpl::divides<N_type, den_type>::value));
105         BOOST_STATIC_CONSTANT(integer_type, Denominator =
106             (::boost::mpl::divides<D_type, den_type>::value));
107 
108         /// INTERNAL ONLY
109         typedef static_rational<N,D>    this_type;
110 
111         /// static_rational<N,D> reduced by GCD
112         typedef static_rational<
113             (::boost::mpl::divides<N_type, den_type>::value),
114             (::boost::mpl::divides<D_type, den_type>::value)
115         >  type;
116 
numerator()117         static BOOST_CONSTEXPR integer_type numerator()     { return Numerator; }
denominator()118         static BOOST_CONSTEXPR integer_type denominator()   { return Denominator; }
119 
120         // INTERNAL ONLY
static_rational()121         BOOST_CONSTEXPR static_rational() { }
122         //~static_rational() { }
123 };
124 #else
125 template<integer_type N,integer_type D = 1>
126 class static_rational
127 {
128     private:
129 
130         BOOST_STATIC_CONSTEXPR integer_type nabs = static_abs<N>::value,
131                                             dabs = static_abs<D>::value;
132 
133         /// greatest common divisor of N and D
134         // need cast to signed because static_gcd returns unsigned long
135         BOOST_STATIC_CONSTEXPR integer_type den =
136             static_cast<integer_type>(boost::integer::static_gcd<nabs,dabs>::value) * ((D < 0) ? -1 : 1);
137 
138     public:
139         // for mpl arithmetic support
140         typedef detail::static_rational_tag tag;
141 
142         BOOST_STATIC_CONSTEXPR integer_type Numerator = N/den,
143             Denominator = D/den;
144 
145         /// INTERNAL ONLY
146         typedef static_rational<N,D>    this_type;
147 
148         /// static_rational<N,D> reduced by GCD
149         typedef static_rational<Numerator,Denominator>  type;
150 
numerator()151         static BOOST_CONSTEXPR integer_type numerator()     { return Numerator; }
denominator()152         static BOOST_CONSTEXPR integer_type denominator()   { return Denominator; }
153 
154         // INTERNAL ONLY
static_rational()155         BOOST_CONSTEXPR static_rational() { }
156         //~static_rational() { }
157 };
158 #endif
159 
160 }
161 
162 }
163 
164 #if BOOST_UNITS_HAS_BOOST_TYPEOF
165 
166 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
167 
168 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::static_rational, (long)(long))
169 
170 #endif
171 
172 namespace boost {
173 
174 namespace units {
175 
176 // prohibit zero denominator
177 template<integer_type N> class static_rational<N,0>;
178 
179 /// get decimal value of @c static_rational
180 template<class T,integer_type N,integer_type D>
181 inline BOOST_CONSTEXPR typename divide_typeof_helper<T,T>::type
value(const static_rational<N,D> &)182 value(const static_rational<N,D>&)
183 {
184     return T(N)/T(D);
185 }
186 
187 } // namespace units
188 
189 #ifndef BOOST_UNITS_DOXYGEN
190 
191 namespace mpl {
192 
193 #ifdef __BORLANDC__
194 
195 template<>
196 struct plus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
197 {
198     template<class T0, class T1>
199     struct apply {
200         typedef typename boost::units::static_rational<
201             ::boost::mpl::plus<
202                 boost::mpl::times<typename T0::N_type, typename T1::D_type>,
203                 boost::mpl::times<typename T1::N_type, typename T0::D_type>
204             >::value,
205             ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
206         >::type type;
207     };
208 };
209 
210 template<>
211 struct minus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
212 {
213     template<class T0, class T1>
214     struct apply {
215         typedef typename boost::units::static_rational<
216             ::boost::mpl::minus<
217                 boost::mpl::times<typename T0::N_type, typename T1::D_type>,
218                 boost::mpl::times<typename T1::N_type, typename T0::D_type>
219             >::value,
220             ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
221         >::type type;
222     };
223 };
224 
225 template<>
226 struct times_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
227 {
228     template<class T0, class T1>
229     struct apply {
230         typedef typename boost::units::static_rational<
231             ::boost::mpl::times<typename T0::N_type, typename T1::N_type>::value,
232             ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
233         >::type type;
234     };
235 };
236 
237 template<>
238 struct divides_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
239 {
240     template<class T0, class T1>
241     struct apply {
242         typedef typename boost::units::static_rational<
243             ::boost::mpl::times<typename T0::N_type, typename T1::D_type>::value,
244             ::boost::mpl::times<typename T0::D_type, typename T1::N_type>::value
245         >::type type;
246     };
247 };
248 
249 template<>
250 struct negate_impl<boost::units::detail::static_rational_tag>
251 {
252     template<class T0>
253     struct apply {
254         typedef typename boost::units::static_rational<
255             ::boost::mpl::negate<typename T0::N_type>::value,
256             ::boost::mpl::identity<T0>::type::Denominator
257         >::type type;
258     };
259 };
260 
261 template<>
262 struct less_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
263 {
264     template<class T0, class T1>
265     struct apply
266     {
267         typedef mpl::bool_<((mpl::minus<T0, T1>::type::Numerator) < 0)> type;
268     };
269 };
270 
271 #else
272 
273 template<>
274 struct plus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
275 {
276     template<class T0, class T1>
277     struct apply {
278         typedef typename boost::units::static_rational<
279             T0::Numerator*T1::Denominator+T1::Numerator*T0::Denominator,
280             T0::Denominator*T1::Denominator
281         >::type type;
282     };
283 };
284 
285 template<>
286 struct minus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
287 {
288     template<class T0, class T1>
289     struct apply {
290         typedef typename boost::units::static_rational<
291             T0::Numerator*T1::Denominator-T1::Numerator*T0::Denominator,
292             T0::Denominator*T1::Denominator
293         >::type type;
294     };
295 };
296 
297 template<>
298 struct times_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
299 {
300     template<class T0, class T1>
301     struct apply {
302         typedef typename boost::units::static_rational<
303             T0::Numerator*T1::Numerator,
304             T0::Denominator*T1::Denominator
305         >::type type;
306     };
307 };
308 
309 template<>
310 struct divides_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
311 {
312     template<class T0, class T1>
313     struct apply {
314         typedef typename boost::units::static_rational<
315             T0::Numerator*T1::Denominator,
316             T0::Denominator*T1::Numerator
317         >::type type;
318     };
319 };
320 
321 template<>
322 struct negate_impl<boost::units::detail::static_rational_tag>
323 {
324     template<class T0>
325     struct apply {
326         typedef typename boost::units::static_rational<-T0::Numerator,T0::Denominator>::type type;
327     };
328 };
329 
330 template<>
331 struct less_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
332 {
333     template<class T0, class T1>
334     struct apply
335     {
336         typedef mpl::bool_<((mpl::minus<T0, T1>::type::Numerator) < 0)> type;
337     };
338 };
339 
340 #endif
341 
342 
343 }
344 
345 #endif
346 
347 } // namespace boost
348 
349 #endif // BOOST_UNITS_STATIC_RATIONAL_HPP
350