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 | |
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 |
125 | template<integer_type N,integer_type D = 1> |
126 | class 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 | |
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 typename divide_typeof_helper<T,T>::type |
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 | |