/work/workdir/UnpackedTarball/boost/boost/rational.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Boost rational.hpp header file ------------------------------------------// |
2 | | |
3 | | // (C) Copyright Paul Moore 1999. Permission to copy, use, modify, sell and |
4 | | // distribute this software is granted provided this copyright notice appears |
5 | | // in all copies. This software is provided "as is" without express or |
6 | | // implied warranty, and with no claim as to its suitability for any purpose. |
7 | | |
8 | | // boostinspect:nolicense (don't complain about the lack of a Boost license) |
9 | | // (Paul Moore hasn't been in contact for years, so there's no way to change the |
10 | | // license.) |
11 | | |
12 | | // See http://www.boost.org/libs/rational for documentation. |
13 | | |
14 | | // Credits: |
15 | | // Thanks to the boost mailing list in general for useful comments. |
16 | | // Particular contributions included: |
17 | | // Andrew D Jewell, for reminding me to take care to avoid overflow |
18 | | // Ed Brey, for many comments, including picking up on some dreadful typos |
19 | | // Stephen Silver contributed the test suite and comments on user-defined |
20 | | // IntType |
21 | | // Nickolay Mladenov, for the implementation of operator+= |
22 | | |
23 | | // Revision History |
24 | | // 12 Nov 20 Fix operators to work with C++20 rules (Glen Joseph Fernandes) |
25 | | // 02 Sep 13 Remove unneeded forward declarations; tweak private helper |
26 | | // function (Daryle Walker) |
27 | | // 30 Aug 13 Improve exception safety of "assign"; start modernizing I/O code |
28 | | // (Daryle Walker) |
29 | | // 27 Aug 13 Add cross-version constructor template, plus some private helper |
30 | | // functions; add constructor to exception class to take custom |
31 | | // messages (Daryle Walker) |
32 | | // 25 Aug 13 Add constexpr qualification wherever possible (Daryle Walker) |
33 | | // 05 May 12 Reduced use of implicit gcd (Mario Lang) |
34 | | // 05 Nov 06 Change rational_cast to not depend on division between different |
35 | | // types (Daryle Walker) |
36 | | // 04 Nov 06 Off-load GCD and LCM to Boost.Integer; add some invariant checks; |
37 | | // add std::numeric_limits<> requirement to help GCD (Daryle Walker) |
38 | | // 31 Oct 06 Recoded both operator< to use round-to-negative-infinity |
39 | | // divisions; the rational-value version now uses continued fraction |
40 | | // expansion to avoid overflows, for bug #798357 (Daryle Walker) |
41 | | // 20 Oct 06 Fix operator bool_type for CW 8.3 (Joaquín M López Muñoz) |
42 | | // 18 Oct 06 Use EXPLICIT_TEMPLATE_TYPE helper macros from Boost.Config |
43 | | // (Joaquín M López Muñoz) |
44 | | // 27 Dec 05 Add Boolean conversion operator (Daryle Walker) |
45 | | // 28 Sep 02 Use _left versions of operators from operators.hpp |
46 | | // 05 Jul 01 Recode gcd(), avoiding std::swap (Helmut Zeisel) |
47 | | // 03 Mar 01 Workarounds for Intel C++ 5.0 (David Abrahams) |
48 | | // 05 Feb 01 Update operator>> to tighten up input syntax |
49 | | // 05 Feb 01 Final tidy up of gcd code prior to the new release |
50 | | // 27 Jan 01 Recode abs() without relying on abs(IntType) |
51 | | // 21 Jan 01 Include Nickolay Mladenov's operator+= algorithm, |
52 | | // tidy up a number of areas, use newer features of operators.hpp |
53 | | // (reduces space overhead to zero), add operator!, |
54 | | // introduce explicit mixed-mode arithmetic operations |
55 | | // 12 Jan 01 Include fixes to handle a user-defined IntType better |
56 | | // 19 Nov 00 Throw on divide by zero in operator /= (John (EBo) David) |
57 | | // 23 Jun 00 Incorporate changes from Mark Rodgers for Borland C++ |
58 | | // 22 Jun 00 Change _MSC_VER to BOOST_MSVC so other compilers are not |
59 | | // affected (Beman Dawes) |
60 | | // 6 Mar 00 Fix operator-= normalization, #include <string> (Jens Maurer) |
61 | | // 14 Dec 99 Modifications based on comments from the boost list |
62 | | // 09 Dec 99 Initial Version (Paul Moore) |
63 | | |
64 | | #ifndef BOOST_RATIONAL_HPP |
65 | | #define BOOST_RATIONAL_HPP |
66 | | |
67 | | #include <boost/config.hpp> // for BOOST_NO_STDC_NAMESPACE, BOOST_MSVC, etc |
68 | | #ifndef BOOST_NO_IOSTREAM |
69 | | #include <iomanip> // for std::setw |
70 | | #include <ios> // for std::noskipws, streamsize |
71 | | #include <istream> // for std::istream |
72 | | #include <ostream> // for std::ostream |
73 | | #include <sstream> // for std::ostringstream |
74 | | #endif |
75 | | #include <cstddef> // for NULL |
76 | | #include <stdexcept> // for std::domain_error |
77 | | #include <string> // for std::string implicit constructor |
78 | | #include <cstdlib> // for std::abs |
79 | | #include <boost/call_traits.hpp> // for boost::call_traits |
80 | | #include <boost/detail/workaround.hpp> // for BOOST_WORKAROUND |
81 | | #include <boost/assert.hpp> // for BOOST_ASSERT |
82 | | #include <boost/integer/common_factor_rt.hpp> // for boost::integer::gcd, lcm |
83 | | #include <limits> // for std::numeric_limits |
84 | | #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT |
85 | | #include <boost/throw_exception.hpp> |
86 | | #include <boost/utility/enable_if.hpp> |
87 | | #include <boost/type_traits/is_convertible.hpp> |
88 | | #include <boost/type_traits/is_class.hpp> |
89 | | #include <boost/type_traits/is_same.hpp> |
90 | | #include <boost/type_traits/is_array.hpp> |
91 | | |
92 | | // Control whether depreciated GCD and LCM functions are included (default: yes) |
93 | | #ifndef BOOST_CONTROL_RATIONAL_HAS_GCD |
94 | | #define BOOST_CONTROL_RATIONAL_HAS_GCD 1 |
95 | | #endif |
96 | | |
97 | | namespace boost { |
98 | | |
99 | | #if BOOST_CONTROL_RATIONAL_HAS_GCD |
100 | | template <typename IntType> |
101 | | IntType gcd(IntType n, IntType m) |
102 | | { |
103 | | // Defer to the version in Boost.Integer |
104 | | return integer::gcd( n, m ); |
105 | | } |
106 | | |
107 | | template <typename IntType> |
108 | | IntType lcm(IntType n, IntType m) |
109 | | { |
110 | | // Defer to the version in Boost.Integer |
111 | | return integer::lcm( n, m ); |
112 | | } |
113 | | #endif // BOOST_CONTROL_RATIONAL_HAS_GCD |
114 | | |
115 | | namespace rational_detail{ |
116 | | |
117 | | template <class FromInt, class ToInt, typename Enable = void> |
118 | | struct is_compatible_integer; |
119 | | |
120 | | template <class FromInt, class ToInt> |
121 | | struct is_compatible_integer<FromInt, ToInt, typename enable_if_c<!is_array<FromInt>::value>::type> |
122 | | { |
123 | | BOOST_STATIC_CONSTANT(bool, value = ((std::numeric_limits<FromInt>::is_specialized && std::numeric_limits<FromInt>::is_integer |
124 | | && (std::numeric_limits<FromInt>::digits <= std::numeric_limits<ToInt>::digits) |
125 | | && (std::numeric_limits<FromInt>::radix == std::numeric_limits<ToInt>::radix) |
126 | | && ((std::numeric_limits<FromInt>::is_signed == false) || (std::numeric_limits<ToInt>::is_signed == true)) |
127 | | && is_convertible<FromInt, ToInt>::value) |
128 | | || is_same<FromInt, ToInt>::value) |
129 | | || (is_class<ToInt>::value && is_class<FromInt>::value && is_convertible<FromInt, ToInt>::value)); |
130 | | }; |
131 | | |
132 | | template <class FromInt, class ToInt> |
133 | | struct is_compatible_integer<FromInt, ToInt, typename enable_if_c<is_array<FromInt>::value>::type> |
134 | | { |
135 | | BOOST_STATIC_CONSTANT(bool, value = false); |
136 | | }; |
137 | | |
138 | | template <class FromInt, class ToInt, typename Enable = void> |
139 | | struct is_backward_compatible_integer; |
140 | | |
141 | | template <class FromInt, class ToInt> |
142 | | struct is_backward_compatible_integer<FromInt, ToInt, typename enable_if_c<!is_array<FromInt>::value>::type> |
143 | | { |
144 | | BOOST_STATIC_CONSTANT(bool, value = (std::numeric_limits<FromInt>::is_specialized && std::numeric_limits<FromInt>::is_integer |
145 | | && !is_compatible_integer<FromInt, ToInt>::value |
146 | | && (std::numeric_limits<FromInt>::radix == std::numeric_limits<ToInt>::radix) |
147 | | && is_convertible<FromInt, ToInt>::value)); |
148 | | }; |
149 | | |
150 | | template <class FromInt, class ToInt> |
151 | | struct is_backward_compatible_integer<FromInt, ToInt, typename enable_if_c<is_array<FromInt>::value>::type> |
152 | | { |
153 | | BOOST_STATIC_CONSTANT(bool, value = false); |
154 | | }; |
155 | | } |
156 | | |
157 | | class bad_rational : public std::domain_error |
158 | | { |
159 | | public: |
160 | 4.70k | explicit bad_rational() : std::domain_error("bad rational: zero denominator") {} |
161 | 0 | explicit bad_rational( char const *what ) : std::domain_error( what ) {} |
162 | | }; |
163 | | |
164 | | template <typename IntType> |
165 | | class rational |
166 | | { |
167 | | // Class-wide pre-conditions |
168 | | BOOST_STATIC_ASSERT( ::std::numeric_limits<IntType>::is_specialized ); |
169 | | |
170 | | // Helper types |
171 | | typedef typename boost::call_traits<IntType>::param_type param_type; |
172 | | |
173 | | struct helper { IntType parts[2]; }; |
174 | | typedef IntType (helper::* bool_type)[2]; |
175 | | |
176 | | public: |
177 | | // Component type |
178 | | typedef IntType int_type; |
179 | | |
180 | | BOOST_CONSTEXPR |
181 | | rational() : num(0), den(1) {} |
182 | | |
183 | | template <class T>//, typename enable_if_c<!is_array<T>::value>::type> |
184 | | BOOST_CONSTEXPR rational(const T& n, typename enable_if_c< |
185 | | rational_detail::is_compatible_integer<T, IntType>::value |
186 | 146M | >::type const* = 0) : num(n), den(1) {} |
187 | | |
188 | | template <class T, class U> |
189 | | BOOST_CXX14_CONSTEXPR rational(const T& n, const U& d, typename enable_if_c< |
190 | | rational_detail::is_compatible_integer<T, IntType>::value && rational_detail::is_compatible_integer<U, IntType>::value |
191 | 621M | >::type const* = 0) : num(n), den(d) { |
192 | 621M | normalize(); |
193 | 621M | } |
194 | | |
195 | | template < typename NewType > |
196 | | BOOST_CONSTEXPR explicit |
197 | | rational(rational<NewType> const &r, typename enable_if_c<rational_detail::is_compatible_integer<NewType, IntType>::value>::type const* = 0) |
198 | | : num(r.numerator()), den(is_normalized(int_type(r.numerator()), |
199 | | int_type(r.denominator())) ? r.denominator() : |
200 | | (BOOST_THROW_EXCEPTION(bad_rational("bad rational: denormalized conversion")), 0)){} |
201 | | |
202 | | template < typename NewType > |
203 | | BOOST_CONSTEXPR explicit |
204 | | rational(rational<NewType> const &r, typename disable_if_c<rational_detail::is_compatible_integer<NewType, IntType>::value>::type const* = 0) |
205 | | : num(r.numerator()), den(is_normalized(int_type(r.numerator()), |
206 | | int_type(r.denominator())) && is_safe_narrowing_conversion(r.denominator()) && is_safe_narrowing_conversion(r.numerator()) ? r.denominator() : |
207 | | (BOOST_THROW_EXCEPTION(bad_rational("bad rational: denormalized conversion")), 0)){} |
208 | | // Default copy constructor and assignment are fine |
209 | | |
210 | | // Add assignment from IntType |
211 | | template <class T> |
212 | | BOOST_CXX14_CONSTEXPR typename enable_if_c< |
213 | | rational_detail::is_compatible_integer<T, IntType>::value, rational & |
214 | | >::type operator=(const T& n) { return assign(static_cast<IntType>(n), static_cast<IntType>(1)); } |
215 | | |
216 | | // Assign in place |
217 | | template <class T, class U> |
218 | | BOOST_CXX14_CONSTEXPR typename enable_if_c< |
219 | | rational_detail::is_compatible_integer<T, IntType>::value && rational_detail::is_compatible_integer<U, IntType>::value, rational & |
220 | | >::type assign(const T& n, const U& d) |
221 | 31.5k | { |
222 | 31.5k | return *this = rational<IntType>(static_cast<IntType>(n), static_cast<IntType>(d)); |
223 | 31.5k | } |
224 | | // |
225 | | // The following overloads should probably *not* be provided - |
226 | | // but are provided for backwards compatibity reasons only. |
227 | | // These allow for construction/assignment from types that |
228 | | // are wider than IntType only if there is an implicit |
229 | | // conversion from T to IntType, they will throw a bad_rational |
230 | | // if the conversion results in loss of precision or undefined behaviour. |
231 | | // |
232 | | template <class T>//, typename enable_if_c<!is_array<T>::value>::type> |
233 | | BOOST_CXX14_CONSTEXPR rational(const T& n, typename enable_if_c< |
234 | | rational_detail::is_backward_compatible_integer<T, IntType>::value |
235 | | >::type const* = 0) |
236 | | { |
237 | | assign(n, static_cast<T>(1)); |
238 | | } |
239 | | template <class T, class U> |
240 | | BOOST_CXX14_CONSTEXPR rational(const T& n, const U& d, typename enable_if_c< |
241 | | (!rational_detail::is_compatible_integer<T, IntType>::value |
242 | | || !rational_detail::is_compatible_integer<U, IntType>::value) |
243 | | && std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer |
244 | | && (std::numeric_limits<T>::radix == std::numeric_limits<IntType>::radix) |
245 | | && is_convertible<T, IntType>::value && |
246 | | std::numeric_limits<U>::is_specialized && std::numeric_limits<U>::is_integer |
247 | | && (std::numeric_limits<U>::radix == std::numeric_limits<IntType>::radix) |
248 | | && is_convertible<U, IntType>::value |
249 | | >::type const* = 0) |
250 | | { |
251 | | assign(n, d); |
252 | | } |
253 | | template <class T> |
254 | | BOOST_CXX14_CONSTEXPR typename enable_if_c< |
255 | | std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer |
256 | | && !rational_detail::is_compatible_integer<T, IntType>::value |
257 | | && (std::numeric_limits<T>::radix == std::numeric_limits<IntType>::radix) |
258 | | && is_convertible<T, IntType>::value, |
259 | | rational & |
260 | | >::type operator=(const T& n) { return assign(n, static_cast<T>(1)); } |
261 | | |
262 | | template <class T, class U> |
263 | | BOOST_CXX14_CONSTEXPR typename enable_if_c< |
264 | | (!rational_detail::is_compatible_integer<T, IntType>::value |
265 | | || !rational_detail::is_compatible_integer<U, IntType>::value) |
266 | | && std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer |
267 | | && (std::numeric_limits<T>::radix == std::numeric_limits<IntType>::radix) |
268 | | && is_convertible<T, IntType>::value && |
269 | | std::numeric_limits<U>::is_specialized && std::numeric_limits<U>::is_integer |
270 | | && (std::numeric_limits<U>::radix == std::numeric_limits<IntType>::radix) |
271 | | && is_convertible<U, IntType>::value, |
272 | | rational & |
273 | | >::type assign(const T& n, const U& d) |
274 | | { |
275 | | if(!is_safe_narrowing_conversion(n) || !is_safe_narrowing_conversion(d)) |
276 | | BOOST_THROW_EXCEPTION(bad_rational()); |
277 | | return *this = rational<IntType>(static_cast<IntType>(n), static_cast<IntType>(d)); |
278 | | } |
279 | | |
280 | | // Access to representation |
281 | | BOOST_CONSTEXPR |
282 | 1.16G | const IntType& numerator() const { return num; } |
283 | | BOOST_CONSTEXPR |
284 | 1.16G | const IntType& denominator() const { return den; } |
285 | | |
286 | | // Arithmetic assignment operators |
287 | | BOOST_CXX14_CONSTEXPR rational& operator+= (const rational& r); |
288 | | BOOST_CXX14_CONSTEXPR rational& operator-= (const rational& r); |
289 | | BOOST_CXX14_CONSTEXPR rational& operator*= (const rational& r); |
290 | | BOOST_CXX14_CONSTEXPR rational& operator/= (const rational& r); |
291 | | |
292 | | template <class T> |
293 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, rational&>::type operator+= (const T& i) |
294 | | { |
295 | | num += i * den; |
296 | | return *this; |
297 | | } |
298 | | template <class T> |
299 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, rational&>::type operator-= (const T& i) |
300 | | { |
301 | | num -= i * den; |
302 | | return *this; |
303 | | } |
304 | | template <class T> |
305 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, rational&>::type operator*= (const T& i) |
306 | | { |
307 | | // Avoid overflow and preserve normalization |
308 | | IntType gcd = integer::gcd(static_cast<IntType>(i), den); |
309 | | num *= i / gcd; |
310 | | den /= gcd; |
311 | | return *this; |
312 | | } |
313 | | template <class T> |
314 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, rational&>::type operator/= (const T& i) |
315 | | { |
316 | | // Avoid repeated construction |
317 | | IntType const zero(0); |
318 | | |
319 | | if(i == zero) BOOST_THROW_EXCEPTION(bad_rational()); |
320 | | if(num == zero) return *this; |
321 | | |
322 | | // Avoid overflow and preserve normalization |
323 | | IntType const gcd = integer::gcd(num, static_cast<IntType>(i)); |
324 | | num /= gcd; |
325 | | den *= i / gcd; |
326 | | |
327 | | if(den < zero) { |
328 | | num = -num; |
329 | | den = -den; |
330 | | } |
331 | | |
332 | | return *this; |
333 | | } |
334 | | |
335 | | // Increment and decrement |
336 | | BOOST_CXX14_CONSTEXPR const rational& operator++() { num += den; return *this; } |
337 | | BOOST_CXX14_CONSTEXPR const rational& operator--() { num -= den; return *this; } |
338 | | |
339 | | BOOST_CXX14_CONSTEXPR rational operator++(int) |
340 | | { |
341 | | rational t(*this); |
342 | | ++(*this); |
343 | | return t; |
344 | | } |
345 | | BOOST_CXX14_CONSTEXPR rational operator--(int) |
346 | | { |
347 | | rational t(*this); |
348 | | --(*this); |
349 | | return t; |
350 | | } |
351 | | |
352 | | // Operator not |
353 | | BOOST_CONSTEXPR |
354 | 195 | bool operator!() const { return !num; } |
355 | | |
356 | | // Boolean conversion |
357 | | |
358 | | #if BOOST_WORKAROUND(__MWERKS__,<=0x3003) |
359 | | // The "ISO C++ Template Parser" option in CW 8.3 chokes on the |
360 | | // following, hence we selectively disable that option for the |
361 | | // offending memfun. |
362 | | #pragma parse_mfunc_templ off |
363 | | #endif |
364 | | |
365 | | BOOST_CONSTEXPR |
366 | | operator bool_type() const { return operator !() ? 0 : &helper::parts; } |
367 | | |
368 | | #if BOOST_WORKAROUND(__MWERKS__,<=0x3003) |
369 | | #pragma parse_mfunc_templ reset |
370 | | #endif |
371 | | |
372 | | // Comparison operators |
373 | | BOOST_CXX14_CONSTEXPR bool operator< (const rational& r) const; |
374 | 0 | BOOST_CXX14_CONSTEXPR bool operator> (const rational& r) const { return r < *this; } |
375 | | BOOST_CONSTEXPR |
376 | | bool operator== (const rational& r) const; |
377 | | |
378 | | template <class T> |
379 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, bool>::type operator< (const T& i) const |
380 | | { |
381 | | // Avoid repeated construction |
382 | | int_type const zero(0); |
383 | | |
384 | | // Break value into mixed-fraction form, w/ always-nonnegative remainder |
385 | | BOOST_ASSERT(this->den > zero); |
386 | | int_type q = this->num / this->den, r = this->num % this->den; |
387 | | while(r < zero) { r += this->den; --q; } |
388 | | |
389 | | // Compare with just the quotient, since the remainder always bumps the |
390 | | // value up. [Since q = floor(n/d), and if n/d < i then q < i, if n/d == i |
391 | | // then q == i, if n/d == i + r/d then q == i, and if n/d >= i + 1 then |
392 | | // q >= i + 1 > i; therefore n/d < i iff q < i.] |
393 | | return q < i; |
394 | | } |
395 | | template <class T> |
396 | | BOOST_CXX14_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, bool>::type operator>(const T& i) const |
397 | | { |
398 | | return operator==(i) ? false : !operator<(i); |
399 | | } |
400 | | template <class T> |
401 | | BOOST_CONSTEXPR typename boost::enable_if_c<rational_detail::is_compatible_integer<T, IntType>::value, bool>::type operator== (const T& i) const |
402 | | { |
403 | | return ((den == IntType(1)) && (num == i)); |
404 | | } |
405 | | |
406 | | private: |
407 | | // Implementation - numerator and denominator (normalized). |
408 | | // Other possibilities - separate whole-part, or sign, fields? |
409 | | IntType num; |
410 | | IntType den; |
411 | | |
412 | | // Helper functions |
413 | | static BOOST_CONSTEXPR |
414 | | int_type inner_gcd( param_type a, param_type b, int_type const &zero = |
415 | | int_type(0) ) |
416 | | { return b == zero ? a : inner_gcd(b, a % b, zero); } |
417 | | |
418 | | static BOOST_CONSTEXPR |
419 | | int_type inner_abs( param_type x, int_type const &zero = int_type(0) ) |
420 | | { return x < zero ? -x : +x; } |
421 | | |
422 | | // Representation note: Fractions are kept in normalized form at all |
423 | | // times. normalized form is defined as gcd(num,den) == 1 and den > 0. |
424 | | // In particular, note that the implementation of abs() below relies |
425 | | // on den always being positive. |
426 | | BOOST_CXX14_CONSTEXPR bool test_invariant() const; |
427 | | BOOST_CXX14_CONSTEXPR void normalize(); |
428 | | |
429 | | static BOOST_CONSTEXPR |
430 | | bool is_normalized( param_type n, param_type d, int_type const &zero = |
431 | | int_type(0), int_type const &one = int_type(1) ) |
432 | | { |
433 | | return d > zero && ( n != zero || d == one ) && inner_abs( inner_gcd(n, |
434 | | d, zero), zero ) == one; |
435 | | } |
436 | | // |
437 | | // Conversion checks: |
438 | | // |
439 | | // (1) From an unsigned type with more digits than IntType: |
440 | | // |
441 | | template <class T> |
442 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits > std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == false), bool>::type is_safe_narrowing_conversion(const T& val) |
443 | | { |
444 | | return val < (T(1) << std::numeric_limits<IntType>::digits); |
445 | | } |
446 | | // |
447 | | // (2) From a signed type with more digits than IntType, and IntType also signed: |
448 | | // |
449 | | template <class T> |
450 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits > std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == true) && (std::numeric_limits<IntType>::is_signed == true), bool>::type is_safe_narrowing_conversion(const T& val) |
451 | | { |
452 | | // Note that this check assumes IntType has a 2's complement representation, |
453 | | // we don't want to try to convert a std::numeric_limits<IntType>::min() to |
454 | | // a T because that conversion may not be allowed (this happens when IntType |
455 | | // is from Boost.Multiprecision). |
456 | | return (val < (T(1) << std::numeric_limits<IntType>::digits)) && (val >= -(T(1) << std::numeric_limits<IntType>::digits)); |
457 | | } |
458 | | // |
459 | | // (3) From a signed type with more digits than IntType, and IntType unsigned: |
460 | | // |
461 | | template <class T> |
462 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits > std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == true) && (std::numeric_limits<IntType>::is_signed == false), bool>::type is_safe_narrowing_conversion(const T& val) |
463 | | { |
464 | | return (val < (T(1) << std::numeric_limits<IntType>::digits)) && (val >= 0); |
465 | | } |
466 | | // |
467 | | // (4) From a signed type with fewer digits than IntType, and IntType unsigned: |
468 | | // |
469 | | template <class T> |
470 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits <= std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == true) && (std::numeric_limits<IntType>::is_signed == false), bool>::type is_safe_narrowing_conversion(const T& val) |
471 | | { |
472 | | return val >= 0; |
473 | | } |
474 | | // |
475 | | // (5) From an unsigned type with fewer digits than IntType, and IntType signed: |
476 | | // |
477 | | template <class T> |
478 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits <= std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == false) && (std::numeric_limits<IntType>::is_signed == true), bool>::type is_safe_narrowing_conversion(const T&) |
479 | | { |
480 | | return true; |
481 | | } |
482 | | // |
483 | | // (6) From an unsigned type with fewer digits than IntType, and IntType unsigned: |
484 | | // |
485 | | template <class T> |
486 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits <= std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == false) && (std::numeric_limits<IntType>::is_signed == false), bool>::type is_safe_narrowing_conversion(const T&) |
487 | | { |
488 | | return true; |
489 | | } |
490 | | // |
491 | | // (7) From an signed type with fewer digits than IntType, and IntType signed: |
492 | | // |
493 | | template <class T> |
494 | | BOOST_CONSTEXPR static typename boost::enable_if_c<(std::numeric_limits<T>::digits <= std::numeric_limits<IntType>::digits) && (std::numeric_limits<T>::is_signed == true) && (std::numeric_limits<IntType>::is_signed == true), bool>::type is_safe_narrowing_conversion(const T&) |
495 | | { |
496 | | return true; |
497 | | } |
498 | | }; |
499 | | |
500 | | // Unary plus and minus |
501 | | template <typename IntType> |
502 | | BOOST_CONSTEXPR |
503 | | inline rational<IntType> operator+ (const rational<IntType>& r) |
504 | | { |
505 | | return r; |
506 | | } |
507 | | |
508 | | template <typename IntType> |
509 | | BOOST_CXX14_CONSTEXPR |
510 | | inline rational<IntType> operator- (const rational<IntType>& r) |
511 | | { |
512 | | return rational<IntType>(static_cast<IntType>(-r.numerator()), r.denominator()); |
513 | | } |
514 | | |
515 | | // Arithmetic assignment operators |
516 | | template <typename IntType> |
517 | | BOOST_CXX14_CONSTEXPR rational<IntType>& rational<IntType>::operator+= (const rational<IntType>& r) |
518 | 0 | { |
519 | | // This calculation avoids overflow, and minimises the number of expensive |
520 | | // calculations. Thanks to Nickolay Mladenov for this algorithm. |
521 | | // |
522 | | // Proof: |
523 | | // We have to compute a/b + c/d, where gcd(a,b)=1 and gcd(b,c)=1. |
524 | | // Let g = gcd(b,d), and b = b1*g, d=d1*g. Then gcd(b1,d1)=1 |
525 | | // |
526 | | // The result is (a*d1 + c*b1) / (b1*d1*g). |
527 | | // Now we have to normalize this ratio. |
528 | | // Let's assume h | gcd((a*d1 + c*b1), (b1*d1*g)), and h > 1 |
529 | | // If h | b1 then gcd(h,d1)=1 and hence h|(a*d1+c*b1) => h|a. |
530 | | // But since gcd(a,b1)=1 we have h=1. |
531 | | // Similarly h|d1 leads to h=1. |
532 | | // So we have that h | gcd((a*d1 + c*b1) , (b1*d1*g)) => h|g |
533 | | // Finally we have gcd((a*d1 + c*b1), (b1*d1*g)) = gcd((a*d1 + c*b1), g) |
534 | | // Which proves that instead of normalizing the result, it is better to |
535 | | // divide num and den by gcd((a*d1 + c*b1), g) |
536 | | |
537 | | // Protect against self-modification |
538 | 0 | IntType r_num = r.num; |
539 | 0 | IntType r_den = r.den; |
540 | |
|
541 | 0 | IntType g = integer::gcd(den, r_den); |
542 | 0 | den /= g; // = b1 from the calculations above |
543 | 0 | num = num * (r_den / g) + r_num * den; |
544 | 0 | g = integer::gcd(num, g); |
545 | 0 | num /= g; |
546 | 0 | den *= r_den/g; |
547 | |
|
548 | 0 | return *this; |
549 | 0 | } |
550 | | |
551 | | template <typename IntType> |
552 | | BOOST_CXX14_CONSTEXPR rational<IntType>& rational<IntType>::operator-= (const rational<IntType>& r) |
553 | 1.06k | { |
554 | | // Protect against self-modification |
555 | 1.06k | IntType r_num = r.num; |
556 | 1.06k | IntType r_den = r.den; |
557 | | |
558 | | // This calculation avoids overflow, and minimises the number of expensive |
559 | | // calculations. It corresponds exactly to the += case above |
560 | 1.06k | IntType g = integer::gcd(den, r_den); |
561 | 1.06k | den /= g; |
562 | 1.06k | num = num * (r_den / g) - r_num * den; |
563 | 1.06k | g = integer::gcd(num, g); |
564 | 1.06k | num /= g; |
565 | 1.06k | den *= r_den/g; |
566 | | |
567 | 1.06k | return *this; |
568 | 1.06k | } |
569 | | |
570 | | template <typename IntType> |
571 | | BOOST_CXX14_CONSTEXPR rational<IntType>& rational<IntType>::operator*= (const rational<IntType>& r) |
572 | 202M | { |
573 | | // Protect against self-modification |
574 | 202M | IntType r_num = r.num; |
575 | 202M | IntType r_den = r.den; |
576 | | |
577 | | // Avoid overflow and preserve normalization |
578 | 202M | IntType gcd1 = integer::gcd(num, r_den); |
579 | 202M | IntType gcd2 = integer::gcd(r_num, den); |
580 | 202M | num = (num/gcd1) * (r_num/gcd2); |
581 | 202M | den = (den/gcd2) * (r_den/gcd1); |
582 | 202M | return *this; |
583 | 202M | } |
584 | | |
585 | | template <typename IntType> |
586 | | BOOST_CXX14_CONSTEXPR rational<IntType>& rational<IntType>::operator/= (const rational<IntType>& r) |
587 | 47.6k | { |
588 | | // Protect against self-modification |
589 | 47.6k | IntType r_num = r.num; |
590 | 47.6k | IntType r_den = r.den; |
591 | | |
592 | | // Avoid repeated construction |
593 | 47.6k | IntType zero(0); |
594 | | |
595 | | // Trap division by zero |
596 | 47.6k | if (r_num == zero) |
597 | 0 | BOOST_THROW_EXCEPTION(bad_rational()); |
598 | 47.6k | if (num == zero) |
599 | 147 | return *this; |
600 | | |
601 | | // Avoid overflow and preserve normalization |
602 | 47.4k | IntType gcd1 = integer::gcd(num, r_num); |
603 | 47.4k | IntType gcd2 = integer::gcd(r_den, den); |
604 | 47.4k | num = (num/gcd1) * (r_den/gcd2); |
605 | 47.4k | den = (den/gcd2) * (r_num/gcd1); |
606 | | |
607 | 47.4k | if (den < zero) { |
608 | 0 | num = -num; |
609 | 0 | den = -den; |
610 | 0 | } |
611 | 47.4k | return *this; |
612 | 47.6k | } |
613 | | |
614 | | |
615 | | // |
616 | | // Non-member operators: previously these were provided by Boost.Operator, but these had a number of |
617 | | // drawbacks, most notably, that in order to allow inter-operability with IntType code such as this: |
618 | | // |
619 | | // rational<int> r(3); |
620 | | // assert(r == 3.5); // compiles and passes!! |
621 | | // |
622 | | // Happens to be allowed as well :-( |
623 | | // |
624 | | // There are three possible cases for each operator: |
625 | | // 1) rational op rational. |
626 | | // 2) rational op integer |
627 | | // 3) integer op rational |
628 | | // Cases (1) and (2) are folded into the one function. |
629 | | // |
630 | | template <class IntType, class Arg> |
631 | | BOOST_CXX14_CONSTEXPR |
632 | | inline typename boost::enable_if_c < |
633 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, rational<IntType> >::type |
634 | | operator + (const rational<IntType>& a, const Arg& b) |
635 | | { |
636 | | rational<IntType> t(a); |
637 | | return t += b; |
638 | | } |
639 | | template <class Arg, class IntType> |
640 | | BOOST_CXX14_CONSTEXPR |
641 | | inline typename boost::enable_if_c < |
642 | | rational_detail::is_compatible_integer<Arg, IntType>::value, rational<IntType> >::type |
643 | | operator + (const Arg& b, const rational<IntType>& a) |
644 | | { |
645 | | rational<IntType> t(a); |
646 | | return t += b; |
647 | | } |
648 | | |
649 | | template <class IntType, class Arg> |
650 | | BOOST_CXX14_CONSTEXPR |
651 | | inline typename boost::enable_if_c < |
652 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, rational<IntType> >::type |
653 | | operator - (const rational<IntType>& a, const Arg& b) |
654 | | { |
655 | | rational<IntType> t(a); |
656 | | return t -= b; |
657 | | } |
658 | | template <class Arg, class IntType> |
659 | | BOOST_CXX14_CONSTEXPR |
660 | | inline typename boost::enable_if_c < |
661 | | rational_detail::is_compatible_integer<Arg, IntType>::value, rational<IntType> >::type |
662 | | operator - (const Arg& b, const rational<IntType>& a) |
663 | | { |
664 | | rational<IntType> t(a); |
665 | | return -(t -= b); |
666 | | } |
667 | | |
668 | | template <class IntType, class Arg> |
669 | | BOOST_CXX14_CONSTEXPR |
670 | | inline typename boost::enable_if_c < |
671 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, rational<IntType> >::type |
672 | | operator * (const rational<IntType>& a, const Arg& b) |
673 | | { |
674 | | rational<IntType> t(a); |
675 | | return t *= b; |
676 | | } |
677 | | template <class Arg, class IntType> |
678 | | BOOST_CXX14_CONSTEXPR |
679 | | inline typename boost::enable_if_c < |
680 | | rational_detail::is_compatible_integer<Arg, IntType>::value, rational<IntType> >::type |
681 | | operator * (const Arg& b, const rational<IntType>& a) |
682 | | { |
683 | | rational<IntType> t(a); |
684 | | return t *= b; |
685 | | } |
686 | | |
687 | | template <class IntType, class Arg> |
688 | | BOOST_CXX14_CONSTEXPR |
689 | | inline typename boost::enable_if_c < |
690 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, rational<IntType> >::type |
691 | | operator / (const rational<IntType>& a, const Arg& b) |
692 | | { |
693 | | rational<IntType> t(a); |
694 | | return t /= b; |
695 | | } |
696 | | template <class Arg, class IntType> |
697 | | BOOST_CXX14_CONSTEXPR |
698 | | inline typename boost::enable_if_c < |
699 | | rational_detail::is_compatible_integer<Arg, IntType>::value, rational<IntType> >::type |
700 | | operator / (const Arg& b, const rational<IntType>& a) |
701 | | { |
702 | | rational<IntType> t(b); |
703 | | return t /= a; |
704 | | } |
705 | | |
706 | | template <class IntType, class Arg> |
707 | | BOOST_CXX14_CONSTEXPR |
708 | | inline typename boost::enable_if_c < |
709 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, bool>::type |
710 | | operator <= (const rational<IntType>& a, const Arg& b) |
711 | | { |
712 | | return !a.operator>(b); |
713 | | } |
714 | | template <class Arg, class IntType> |
715 | | BOOST_CXX14_CONSTEXPR |
716 | | inline typename boost::enable_if_c < |
717 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
718 | | operator <= (const Arg& b, const rational<IntType>& a) |
719 | | { |
720 | | return a >= b; |
721 | | } |
722 | | |
723 | | template <class IntType, class Arg> |
724 | | BOOST_CXX14_CONSTEXPR |
725 | | inline typename boost::enable_if_c < |
726 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, bool>::type |
727 | | operator >= (const rational<IntType>& a, const Arg& b) |
728 | | { |
729 | | return !a.operator<(b); |
730 | | } |
731 | | template <class Arg, class IntType> |
732 | | BOOST_CXX14_CONSTEXPR |
733 | | inline typename boost::enable_if_c < |
734 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
735 | | operator >= (const Arg& b, const rational<IntType>& a) |
736 | | { |
737 | | return a <= b; |
738 | | } |
739 | | |
740 | | template <class IntType, class Arg> |
741 | | BOOST_CONSTEXPR |
742 | | inline typename boost::enable_if_c < |
743 | | rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, bool>::type |
744 | | operator != (const rational<IntType>& a, const Arg& b) |
745 | | { |
746 | | return !a.operator==(b); |
747 | | } |
748 | | template <class Arg, class IntType> |
749 | | BOOST_CONSTEXPR |
750 | | inline typename boost::enable_if_c < |
751 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
752 | | operator != (const Arg& b, const rational<IntType>& a) |
753 | | { |
754 | | return !(b == a); |
755 | | } |
756 | | |
757 | | template <class Arg, class IntType> |
758 | | BOOST_CXX14_CONSTEXPR |
759 | | inline typename boost::enable_if_c < |
760 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
761 | | operator < (const Arg& b, const rational<IntType>& a) |
762 | | { |
763 | | return a.operator>(b); |
764 | | } |
765 | | template <class Arg, class IntType> |
766 | | BOOST_CXX14_CONSTEXPR |
767 | | inline typename boost::enable_if_c < |
768 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
769 | | operator > (const Arg& b, const rational<IntType>& a) |
770 | | { |
771 | | return a.operator<(b); |
772 | | } |
773 | | template <class Arg, class IntType> |
774 | | BOOST_CONSTEXPR |
775 | | inline typename boost::enable_if_c < |
776 | | rational_detail::is_compatible_integer<Arg, IntType>::value, bool>::type |
777 | | operator == (const Arg& b, const rational<IntType>& a) |
778 | | { |
779 | | return a.operator==(b); |
780 | | } |
781 | | |
782 | | // Comparison operators |
783 | | template <typename IntType> |
784 | | BOOST_CXX14_CONSTEXPR |
785 | | bool rational<IntType>::operator< (const rational<IntType>& r) const |
786 | 0 | { |
787 | | // Avoid repeated construction |
788 | 0 | int_type const zero( 0 ); |
789 | | |
790 | | // This should really be a class-wide invariant. The reason for these |
791 | | // checks is that for 2's complement systems, INT_MIN has no corresponding |
792 | | // positive, so negating it during normalization keeps it INT_MIN, which |
793 | | // is bad for later calculations that assume a positive denominator. |
794 | 0 | BOOST_ASSERT( this->den > zero ); |
795 | 0 | BOOST_ASSERT( r.den > zero ); |
796 | | |
797 | | // Determine relative order by expanding each value to its simple continued |
798 | | // fraction representation using the Euclidian GCD algorithm. |
799 | 0 | struct { int_type n, d, q, r; } |
800 | 0 | ts = { this->num, this->den, static_cast<int_type>(this->num / this->den), |
801 | 0 | static_cast<int_type>(this->num % this->den) }, |
802 | 0 | rs = { r.num, r.den, static_cast<int_type>(r.num / r.den), |
803 | 0 | static_cast<int_type>(r.num % r.den) }; |
804 | 0 | unsigned reverse = 0u; |
805 | | |
806 | | // Normalize negative moduli by repeatedly adding the (positive) denominator |
807 | | // and decrementing the quotient. Later cycles should have all positive |
808 | | // values, so this only has to be done for the first cycle. (The rules of |
809 | | // C++ require a nonnegative quotient & remainder for a nonnegative dividend |
810 | | // & positive divisor.) |
811 | 0 | while ( ts.r < zero ) { ts.r += ts.d; --ts.q; } |
812 | 0 | while ( rs.r < zero ) { rs.r += rs.d; --rs.q; } |
813 | | |
814 | | // Loop through and compare each variable's continued-fraction components |
815 | 0 | for ( ;; ) |
816 | 0 | { |
817 | | // The quotients of the current cycle are the continued-fraction |
818 | | // components. Comparing two c.f. is comparing their sequences, |
819 | | // stopping at the first difference. |
820 | 0 | if ( ts.q != rs.q ) |
821 | 0 | { |
822 | | // Since reciprocation changes the relative order of two variables, |
823 | | // and c.f. use reciprocals, the less/greater-than test reverses |
824 | | // after each index. (Start w/ non-reversed @ whole-number place.) |
825 | 0 | return reverse ? ts.q > rs.q : ts.q < rs.q; |
826 | 0 | } |
827 | | |
828 | | // Prepare the next cycle |
829 | 0 | reverse ^= 1u; |
830 | |
|
831 | 0 | if ( (ts.r == zero) || (rs.r == zero) ) |
832 | 0 | { |
833 | | // At least one variable's c.f. expansion has ended |
834 | 0 | break; |
835 | 0 | } |
836 | | |
837 | 0 | ts.n = ts.d; ts.d = ts.r; |
838 | 0 | ts.q = ts.n / ts.d; ts.r = ts.n % ts.d; |
839 | 0 | rs.n = rs.d; rs.d = rs.r; |
840 | 0 | rs.q = rs.n / rs.d; rs.r = rs.n % rs.d; |
841 | 0 | } |
842 | | |
843 | | // Compare infinity-valued components for otherwise equal sequences |
844 | 0 | if ( ts.r == rs.r ) |
845 | 0 | { |
846 | | // Both remainders are zero, so the next (and subsequent) c.f. |
847 | | // components for both sequences are infinity. Therefore, the sequences |
848 | | // and their corresponding values are equal. |
849 | 0 | return false; |
850 | 0 | } |
851 | 0 | else |
852 | 0 | { |
853 | | #ifdef BOOST_MSVC |
854 | | #pragma warning(push) |
855 | | #pragma warning(disable:4800) |
856 | | #endif |
857 | | // Exactly one of the remainders is zero, so all following c.f. |
858 | | // components of that variable are infinity, while the other variable |
859 | | // has a finite next c.f. component. So that other variable has the |
860 | | // lesser value (modulo the reversal flag!). |
861 | 0 | return ( ts.r != zero ) != static_cast<bool>( reverse ); |
862 | | #ifdef BOOST_MSVC |
863 | | #pragma warning(pop) |
864 | | #endif |
865 | 0 | } |
866 | 0 | } |
867 | | |
868 | | template <typename IntType> |
869 | | BOOST_CONSTEXPR |
870 | | inline bool rational<IntType>::operator== (const rational<IntType>& r) const |
871 | 5.67M | { |
872 | 5.67M | return ((num == r.num) && (den == r.den)); |
873 | 5.67M | } |
874 | | |
875 | | // Invariant check |
876 | | template <typename IntType> |
877 | | BOOST_CXX14_CONSTEXPR |
878 | | inline bool rational<IntType>::test_invariant() const |
879 | | { |
880 | | return ( this->den > int_type(0) ) && ( integer::gcd(this->num, this->den) == |
881 | | int_type(1) ); |
882 | | } |
883 | | |
884 | | // Normalisation |
885 | | template <typename IntType> |
886 | | BOOST_CXX14_CONSTEXPR void rational<IntType>::normalize() |
887 | 621M | { |
888 | | // Avoid repeated construction |
889 | 621M | IntType zero(0); |
890 | | |
891 | 621M | if (den == zero) |
892 | 0 | BOOST_THROW_EXCEPTION(bad_rational()); |
893 | | |
894 | | // Handle the case of zero separately, to avoid division by zero |
895 | 621M | if (num == zero) { |
896 | 252M | den = IntType(1); |
897 | 252M | return; |
898 | 252M | } |
899 | | |
900 | 368M | IntType g = integer::gcd(num, den); |
901 | | |
902 | 368M | num /= g; |
903 | 368M | den /= g; |
904 | | |
905 | 368M | if (den < -(std::numeric_limits<IntType>::max)()) { |
906 | 0 | BOOST_THROW_EXCEPTION(bad_rational("bad rational: non-zero singular denominator")); |
907 | 0 | } |
908 | | |
909 | | // Ensure that the denominator is positive |
910 | 368M | if (den < zero) { |
911 | 1.78k | num = -num; |
912 | 1.78k | den = -den; |
913 | 1.78k | } |
914 | | |
915 | 368M | BOOST_ASSERT( this->test_invariant() ); |
916 | 368M | } |
917 | | |
918 | | #ifndef BOOST_NO_IOSTREAM |
919 | | namespace detail { |
920 | | |
921 | | // A utility class to reset the format flags for an istream at end |
922 | | // of scope, even in case of exceptions |
923 | | struct resetter { |
924 | 0 | resetter(std::istream& is) : is_(is), f_(is.flags()) {} |
925 | 0 | ~resetter() { is_.flags(f_); } |
926 | | std::istream& is_; |
927 | | std::istream::fmtflags f_; // old GNU c++ lib has no ios_base |
928 | | }; |
929 | | |
930 | | } |
931 | | |
932 | | // Input and output |
933 | | template <typename IntType> |
934 | | std::istream& operator>> (std::istream& is, rational<IntType>& r) |
935 | | { |
936 | | using std::ios; |
937 | | |
938 | | IntType n = IntType(0), d = IntType(1); |
939 | | char c = 0; |
940 | | detail::resetter sentry(is); |
941 | | |
942 | | if ( is >> n ) |
943 | | { |
944 | | if ( is.get(c) ) |
945 | | { |
946 | | if ( c == '/' ) |
947 | | { |
948 | | if ( is >> std::noskipws >> d ) |
949 | | try { |
950 | | r.assign( n, d ); |
951 | | } catch ( bad_rational & ) { // normalization fail |
952 | | try { is.setstate(ios::failbit); } |
953 | | catch ( ... ) {} // don't throw ios_base::failure... |
954 | | if ( is.exceptions() & ios::failbit ) |
955 | | throw; // ...but the original exception instead |
956 | | // ELSE: suppress the exception, use just error flags |
957 | | } |
958 | | } |
959 | | else |
960 | | is.setstate( ios::failbit ); |
961 | | } |
962 | | } |
963 | | |
964 | | return is; |
965 | | } |
966 | | |
967 | | // Add manipulators for output format? |
968 | | template <typename IntType> |
969 | | std::ostream& operator<< (std::ostream& os, const rational<IntType>& r) |
970 | | { |
971 | | // The slash directly precedes the denominator, which has no prefixes. |
972 | | std::ostringstream ss; |
973 | | |
974 | | ss.copyfmt( os ); |
975 | | ss.tie( NULL ); |
976 | | ss.exceptions( std::ios::goodbit ); |
977 | | ss.width( 0 ); |
978 | | ss << std::noshowpos << std::noshowbase << '/' << r.denominator(); |
979 | | |
980 | | // The numerator holds the showpos, internal, and showbase flags. |
981 | | std::string const tail = ss.str(); |
982 | | std::streamsize const w = |
983 | | os.width() - static_cast<std::streamsize>( tail.size() ); |
984 | | |
985 | | ss.clear(); |
986 | | ss.str( "" ); |
987 | | ss.flags( os.flags() ); |
988 | | ss << std::setw( w < 0 || (os.flags() & std::ios::adjustfield) != |
989 | | std::ios::internal ? 0 : w ) << r.numerator(); |
990 | | return os << ss.str() + tail; |
991 | | } |
992 | | #endif // BOOST_NO_IOSTREAM |
993 | | |
994 | | // Type conversion |
995 | | template <typename T, typename IntType> |
996 | | BOOST_CONSTEXPR |
997 | | inline T rational_cast(const rational<IntType>& src) |
998 | 181M | { |
999 | 181M | return static_cast<T>(src.numerator())/static_cast<T>(src.denominator()); |
1000 | 181M | } double boost::rational_cast<double, int>(boost::rational<int> const&) Line | Count | Source | 998 | 3.40M | { | 999 | 3.40M | return static_cast<T>(src.numerator())/static_cast<T>(src.denominator()); | 1000 | 3.40M | } |
int boost::rational_cast<int, int>(boost::rational<int> const&) Line | Count | Source | 998 | 177M | { | 999 | 177M | return static_cast<T>(src.numerator())/static_cast<T>(src.denominator()); | 1000 | 177M | } |
|
1001 | | |
1002 | | // Do not use any abs() defined on IntType - it isn't worth it, given the |
1003 | | // difficulties involved (Koenig lookup required, there may not *be* an abs() |
1004 | | // defined, etc etc). |
1005 | | template <typename IntType> |
1006 | | BOOST_CXX14_CONSTEXPR |
1007 | | inline rational<IntType> abs(const rational<IntType>& r) |
1008 | | { |
1009 | | return r.numerator() >= IntType(0)? r: -r; |
1010 | | } |
1011 | | |
1012 | | namespace integer { |
1013 | | |
1014 | | template <typename IntType> |
1015 | | struct gcd_evaluator< rational<IntType> > |
1016 | | { |
1017 | | typedef rational<IntType> result_type, |
1018 | | first_argument_type, second_argument_type; |
1019 | | result_type operator() ( first_argument_type const &a |
1020 | | , second_argument_type const &b |
1021 | | ) const |
1022 | | { |
1023 | | return result_type(integer::gcd(a.numerator(), b.numerator()), |
1024 | | integer::lcm(a.denominator(), b.denominator())); |
1025 | | } |
1026 | | }; |
1027 | | |
1028 | | template <typename IntType> |
1029 | | struct lcm_evaluator< rational<IntType> > |
1030 | | { |
1031 | | typedef rational<IntType> result_type, |
1032 | | first_argument_type, second_argument_type; |
1033 | | result_type operator() ( first_argument_type const &a |
1034 | | , second_argument_type const &b |
1035 | | ) const |
1036 | | { |
1037 | | return result_type(integer::lcm(a.numerator(), b.numerator()), |
1038 | | integer::gcd(a.denominator(), b.denominator())); |
1039 | | } |
1040 | | }; |
1041 | | |
1042 | | } // namespace integer |
1043 | | |
1044 | | } // namespace boost |
1045 | | |
1046 | | #endif // BOOST_RATIONAL_HPP |