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
30namespace boost {
31
32namespace units {
33
34namespace detail {
35
36struct static_rational_tag {};
37
38}
39
40typedef long integer_type;
41
42/// Compile time absolute value.
43template<integer_type Value>
44struct static_abs
45{
46 BOOST_STATIC_CONSTANT(integer_type,value = Value < 0 ? -Value : Value);
47};
48
49// Compile time rational number.
50/**
51This is an implementation of a compile time rational number, where @c static_rational<N,D> represents
52a rational number with numerator @c N and denominator @c D. Because of the potential for ambiguity arising
53from multiple equivalent values of @c static_rational (e.g. @c static_rational<6,2>==static_rational<3>),
54static rationals should always be accessed through @c static_rational<N,D>::type. Template specialization
55prevents instantiation of zero denominators (i.e. @c static_rational<N,0>). The following compile-time
56arithmetic operators are provided for static_rational variables only (no operators are defined between
57long and static_rational):
58 - @c mpl::negate
59 - @c mpl::plus
60 - @c mpl::minus
61 - @c mpl::times
62 - @c mpl::divides
63
64Neither @c static_power nor @c static_root are defined for @c static_rational. This is because template types
65may not be floating point values, while powers and roots of rational numbers can produce floating point
66values.
67*/
68#ifdef __BORLANDC__
69
70template<integer_type X>
71struct make_integral_c {
72 typedef boost::mpl::integral_c<integer_type, X> type;
73};
74
75template<integer_type N,integer_type D = 1>
76class 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
117 static integer_type numerator() { return Numerator; }
118 static integer_type denominator() { return Denominator; }
119
120 // INTERNAL ONLY
121 static_rational() { }
122 //~static_rational() { }
123};
124#else
125template<integer_type N,integer_type D = 1>
126class static_rational
127{
128 private:
129
130 static const 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 static const 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 static const 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
151 static integer_type numerator() { return Numerator; }
152 static integer_type denominator() { return Denominator; }
153
154 // INTERNAL ONLY
155 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
168BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::static_rational, (long)(long))
169
170#endif
171
172namespace boost {
173
174namespace units {
175
176// prohibit zero denominator
177template<integer_type N> class static_rational<N,0>;
178
179/// get decimal value of @c static_rational
180template<class T,integer_type N,integer_type D>
181inline typename divide_typeof_helper<T,T>::type
182value(const static_rational<N,D>&)
183{
184 return T(N)/T(D);
185}
186
187} // namespace units
188
189#ifndef BOOST_UNITS_DOXYGEN
190
191namespace mpl {
192
193#ifdef __BORLANDC__
194
195template<>
196struct 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
210template<>
211struct 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
225template<>
226struct 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
237template<>
238struct 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
249template<>
250struct 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
261template<>
262struct 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
273template<>
274struct 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
285template<>
286struct 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
297template<>
298struct 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
309template<>
310struct 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
321template<>
322struct 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
330template<>
331struct 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

source code of boost/boost/units/static_rational.hpp