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 //  02 Sep 13  Remove unneeded forward declarations; tweak private helper
25 //             function (Daryle Walker)
26 //  30 Aug 13  Improve exception safety of "assign"; start modernizing I/O code
27 //             (Daryle Walker)
28 //  27 Aug 13  Add cross-version constructor template, plus some private helper
29 //             functions; add constructor to exception class to take custom
30 //             messages (Daryle Walker)
31 //  25 Aug 13  Add constexpr qualification wherever possible (Daryle Walker)
32 //  05 May 12  Reduced use of implicit gcd (Mario Lang)
33 //  05 Nov 06  Change rational_cast to not depend on division between different
34 //             types (Daryle Walker)
35 //  04 Nov 06  Off-load GCD and LCM to Boost.Math; add some invariant checks;
36 //             add std::numeric_limits<> requirement to help GCD (Daryle Walker)
37 //  31 Oct 06  Recoded both operator< to use round-to-negative-infinity
38 //             divisions; the rational-value version now uses continued fraction
39 //             expansion to avoid overflows, for bug #798357 (Daryle Walker)
40 //  20 Oct 06  Fix operator bool_type for CW 8.3 (Joaquín M López Muñoz)
41 //  18 Oct 06  Use EXPLICIT_TEMPLATE_TYPE helper macros from Boost.Config
42 //             (Joaquín M López Muñoz)
43 //  27 Dec 05  Add Boolean conversion operator (Daryle Walker)
44 //  28 Sep 02  Use _left versions of operators from operators.hpp
45 //  05 Jul 01  Recode gcd(), avoiding std::swap (Helmut Zeisel)
46 //  03 Mar 01  Workarounds for Intel C++ 5.0 (David Abrahams)
47 //  05 Feb 01  Update operator>> to tighten up input syntax
48 //  05 Feb 01  Final tidy up of gcd code prior to the new release
49 //  27 Jan 01  Recode abs() without relying on abs(IntType)
50 //  21 Jan 01  Include Nickolay Mladenov's operator+= algorithm,
51 //             tidy up a number of areas, use newer features of operators.hpp
52 //             (reduces space overhead to zero), add operator!,
53 //             introduce explicit mixed-mode arithmetic operations
54 //  12 Jan 01  Include fixes to handle a user-defined IntType better
55 //  19 Nov 00  Throw on divide by zero in operator /= (John (EBo) David)
56 //  23 Jun 00  Incorporate changes from Mark Rodgers for Borland C++
57 //  22 Jun 00  Change _MSC_VER to BOOST_MSVC so other compilers are not
58 //             affected (Beman Dawes)
59 //   6 Mar 00  Fix operator-= normalization, #include <string> (Jens Maurer)
60 //  14 Dec 99  Modifications based on comments from the boost list
61 //  09 Dec 99  Initial Version (Paul Moore)
62 
63 #ifndef BOOST_RATIONAL_HPP
64 #define BOOST_RATIONAL_HPP
65 
66 #include <boost/config.hpp>      // for BOOST_NO_STDC_NAMESPACE, BOOST_MSVC, etc
67 #ifndef BOOST_NO_IOSTREAM
68 #include <iomanip>               // for std::setw
69 #include <ios>                   // for std::noskipws, streamsize
70 #include <istream>               // for std::istream
71 #include <ostream>               // for std::ostream
72 #include <sstream>               // for std::ostringstream
73 #endif
74 #include <cstddef>               // for NULL
75 #include <stdexcept>             // for std::domain_error
76 #include <string>                // for std::string implicit constructor
77 #include <boost/operators.hpp>   // for boost::addable etc
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 
86 // Control whether depreciated GCD and LCM functions are included (default: yes)
87 #ifndef BOOST_CONTROL_RATIONAL_HAS_GCD
88 #define BOOST_CONTROL_RATIONAL_HAS_GCD  1
89 #endif
90 
91 namespace boost {
92 
93 #if BOOST_CONTROL_RATIONAL_HAS_GCD
94 template <typename IntType>
gcd(IntType n,IntType m)95 IntType gcd(IntType n, IntType m)
96 {
97     // Defer to the version in Boost.Math
98     return integer::gcd( n, m );
99 }
100 
101 template <typename IntType>
lcm(IntType n,IntType m)102 IntType lcm(IntType n, IntType m)
103 {
104     // Defer to the version in Boost.Math
105     return integer::lcm( n, m );
106 }
107 #endif  // BOOST_CONTROL_RATIONAL_HAS_GCD
108 
109 class bad_rational : public std::domain_error
110 {
111 public:
bad_rational()112     explicit bad_rational() : std::domain_error("bad rational: zero denominator") {}
bad_rational(char const * what)113     explicit bad_rational( char const *what ) : std::domain_error( what ) {}
114 };
115 
116 template <typename IntType>
117 class rational :
118     less_than_comparable < rational<IntType>,
119     equality_comparable < rational<IntType>,
120     less_than_comparable2 < rational<IntType>, IntType,
121     equality_comparable2 < rational<IntType>, IntType,
122     addable < rational<IntType>,
123     subtractable < rational<IntType>,
124     multipliable < rational<IntType>,
125     dividable < rational<IntType>,
126     addable2 < rational<IntType>, IntType,
127     subtractable2 < rational<IntType>, IntType,
128     subtractable2_left < rational<IntType>, IntType,
129     multipliable2 < rational<IntType>, IntType,
130     dividable2 < rational<IntType>, IntType,
131     dividable2_left < rational<IntType>, IntType,
132     incrementable < rational<IntType>,
133     decrementable < rational<IntType>
134     > > > > > > > > > > > > > > > >
135 {
136     // Class-wide pre-conditions
137     BOOST_STATIC_ASSERT( ::std::numeric_limits<IntType>::is_specialized );
138 
139     // Helper types
140     typedef typename boost::call_traits<IntType>::param_type param_type;
141 
142     struct helper { IntType parts[2]; };
143     typedef IntType (helper::* bool_type)[2];
144 
145 public:
146     // Component type
147     typedef IntType int_type;
148 
149     BOOST_CONSTEXPR
rational()150     rational() : num(0), den(1) {}
151     BOOST_CONSTEXPR
rational(param_type n)152     rational(param_type n) : num(n), den(1) {}
rational(param_type n,param_type d)153     rational(param_type n, param_type d) : num(n), den(d) { normalize(); }
154 
155 #ifndef BOOST_NO_MEMBER_TEMPLATES
156     template < typename NewType >
157     BOOST_CONSTEXPR explicit
rational(rational<NewType> const & r)158     rational( rational<NewType> const &r )
159         : num( r.numerator() ), den( is_normalized(int_type( r.numerator() ),
160           int_type( r.denominator() )) ? r.denominator() :
161           throw bad_rational("bad rational: denormalized conversion") )
162     {}
163 #endif
164 
165     // Default copy constructor and assignment are fine
166 
167     // Add assignment from IntType
operator =(param_type i)168     rational& operator=(param_type i) { num = i; den = 1; return *this; }
169 
170     // Assign in place
171     rational& assign(param_type n, param_type d);
172 
173     // Access to representation
174     BOOST_CONSTEXPR
numerator() const175     IntType numerator() const { return num; }
176     BOOST_CONSTEXPR
denominator() const177     IntType denominator() const { return den; }
178 
179     // Arithmetic assignment operators
180     rational& operator+= (const rational& r);
181     rational& operator-= (const rational& r);
182     rational& operator*= (const rational& r);
183     rational& operator/= (const rational& r);
184 
operator +=(param_type i)185     rational& operator+= (param_type i) { num += i * den; return *this; }
operator -=(param_type i)186     rational& operator-= (param_type i) { num -= i * den; return *this; }
187     rational& operator*= (param_type i);
188     rational& operator/= (param_type i);
189 
190     // Increment and decrement
operator ++()191     const rational& operator++() { num += den; return *this; }
operator --()192     const rational& operator--() { num -= den; return *this; }
193 
194     // Operator not
195     BOOST_CONSTEXPR
operator !() const196     bool operator!() const { return !num; }
197 
198     // Boolean conversion
199 
200 #if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
201     // The "ISO C++ Template Parser" option in CW 8.3 chokes on the
202     // following, hence we selectively disable that option for the
203     // offending memfun.
204 #pragma parse_mfunc_templ off
205 #endif
206 
207     BOOST_CONSTEXPR
operator bool_type() const208     operator bool_type() const { return operator !() ? 0 : &helper::parts; }
209 
210 #if BOOST_WORKAROUND(__MWERKS__,<=0x3003)
211 #pragma parse_mfunc_templ reset
212 #endif
213 
214     // Comparison operators
215     bool operator< (const rational& r) const;
216     BOOST_CONSTEXPR
217     bool operator== (const rational& r) const;
218 
219     bool operator< (param_type i) const;
220     bool operator> (param_type i) const;
221     BOOST_CONSTEXPR
222     bool operator== (param_type i) const;
223 
224 private:
225     // Implementation - numerator and denominator (normalized).
226     // Other possibilities - separate whole-part, or sign, fields?
227     IntType num;
228     IntType den;
229 
230     // Helper functions
231     static BOOST_CONSTEXPR
inner_gcd(param_type a,param_type b,int_type const & zero=int_type (0))232     int_type inner_gcd( param_type a, param_type b, int_type const &zero =
233      int_type(0) )
234     { return b == zero ? a : inner_gcd(b, a % b, zero); }
235 
236     static BOOST_CONSTEXPR
inner_abs(param_type x,int_type const & zero=int_type (0))237     int_type inner_abs( param_type x, int_type const &zero = int_type(0) )
238     { return x < zero ? -x : +x; }
239 
240     // Representation note: Fractions are kept in normalized form at all
241     // times. normalized form is defined as gcd(num,den) == 1 and den > 0.
242     // In particular, note that the implementation of abs() below relies
243     // on den always being positive.
244     bool test_invariant() const;
245     void normalize();
246 
247     static BOOST_CONSTEXPR
is_normalized(param_type n,param_type d,int_type const & zero=int_type (0),int_type const & one=int_type (1))248     bool is_normalized( param_type n, param_type d, int_type const &zero =
249      int_type(0), int_type const &one = int_type(1) )
250     {
251         return d > zero && ( n != zero || d == one ) && inner_abs( inner_gcd(n,
252          d, zero), zero ) == one;
253     }
254 };
255 
256 // Assign in place
257 template <typename IntType>
assign(param_type n,param_type d)258 inline rational<IntType>& rational<IntType>::assign(param_type n, param_type d)
259 {
260     return *this = rational( n, d );
261 }
262 
263 // Unary plus and minus
264 template <typename IntType>
265 BOOST_CONSTEXPR
operator +(const rational<IntType> & r)266 inline rational<IntType> operator+ (const rational<IntType>& r)
267 {
268     return r;
269 }
270 
271 template <typename IntType>
operator -(const rational<IntType> & r)272 inline rational<IntType> operator- (const rational<IntType>& r)
273 {
274     return rational<IntType>(-r.numerator(), r.denominator());
275 }
276 
277 // Arithmetic assignment operators
278 template <typename IntType>
operator +=(const rational<IntType> & r)279 rational<IntType>& rational<IntType>::operator+= (const rational<IntType>& r)
280 {
281     // This calculation avoids overflow, and minimises the number of expensive
282     // calculations. Thanks to Nickolay Mladenov for this algorithm.
283     //
284     // Proof:
285     // We have to compute a/b + c/d, where gcd(a,b)=1 and gcd(b,c)=1.
286     // Let g = gcd(b,d), and b = b1*g, d=d1*g. Then gcd(b1,d1)=1
287     //
288     // The result is (a*d1 + c*b1) / (b1*d1*g).
289     // Now we have to normalize this ratio.
290     // Let's assume h | gcd((a*d1 + c*b1), (b1*d1*g)), and h > 1
291     // If h | b1 then gcd(h,d1)=1 and hence h|(a*d1+c*b1) => h|a.
292     // But since gcd(a,b1)=1 we have h=1.
293     // Similarly h|d1 leads to h=1.
294     // So we have that h | gcd((a*d1 + c*b1) , (b1*d1*g)) => h|g
295     // Finally we have gcd((a*d1 + c*b1), (b1*d1*g)) = gcd((a*d1 + c*b1), g)
296     // Which proves that instead of normalizing the result, it is better to
297     // divide num and den by gcd((a*d1 + c*b1), g)
298 
299     // Protect against self-modification
300     IntType r_num = r.num;
301     IntType r_den = r.den;
302 
303     IntType g = integer::gcd(den, r_den);
304     den /= g;  // = b1 from the calculations above
305     num = num * (r_den / g) + r_num * den;
306     g = integer::gcd(num, g);
307     num /= g;
308     den *= r_den/g;
309 
310     return *this;
311 }
312 
313 template <typename IntType>
operator -=(const rational<IntType> & r)314 rational<IntType>& rational<IntType>::operator-= (const rational<IntType>& r)
315 {
316     // Protect against self-modification
317     IntType r_num = r.num;
318     IntType r_den = r.den;
319 
320     // This calculation avoids overflow, and minimises the number of expensive
321     // calculations. It corresponds exactly to the += case above
322     IntType g = integer::gcd(den, r_den);
323     den /= g;
324     num = num * (r_den / g) - r_num * den;
325     g = integer::gcd(num, g);
326     num /= g;
327     den *= r_den/g;
328 
329     return *this;
330 }
331 
332 template <typename IntType>
operator *=(const rational<IntType> & r)333 rational<IntType>& rational<IntType>::operator*= (const rational<IntType>& r)
334 {
335     // Protect against self-modification
336     IntType r_num = r.num;
337     IntType r_den = r.den;
338 
339     // Avoid overflow and preserve normalization
340     IntType gcd1 = integer::gcd(num, r_den);
341     IntType gcd2 = integer::gcd(r_num, den);
342     num = (num/gcd1) * (r_num/gcd2);
343     den = (den/gcd2) * (r_den/gcd1);
344     return *this;
345 }
346 
347 template <typename IntType>
operator /=(const rational<IntType> & r)348 rational<IntType>& rational<IntType>::operator/= (const rational<IntType>& r)
349 {
350     // Protect against self-modification
351     IntType r_num = r.num;
352     IntType r_den = r.den;
353 
354     // Avoid repeated construction
355     IntType zero(0);
356 
357     // Trap division by zero
358     if (r_num == zero)
359         throw bad_rational();
360     if (num == zero)
361         return *this;
362 
363     // Avoid overflow and preserve normalization
364     IntType gcd1 = integer::gcd(num, r_num);
365     IntType gcd2 = integer::gcd(r_den, den);
366     num = (num/gcd1) * (r_den/gcd2);
367     den = (den/gcd2) * (r_num/gcd1);
368 
369     if (den < zero) {
370         num = -num;
371         den = -den;
372     }
373     return *this;
374 }
375 
376 // Mixed-mode operators
377 template <typename IntType>
378 inline rational<IntType>&
operator *=(param_type i)379 rational<IntType>::operator*= (param_type i)
380 {
381     // Avoid overflow and preserve normalization
382     IntType gcd = integer::gcd(i, den);
383     num *= i / gcd;
384     den /= gcd;
385 
386     return *this;
387 }
388 
389 template <typename IntType>
390 rational<IntType>&
operator /=(param_type i)391 rational<IntType>::operator/= (param_type i)
392 {
393     // Avoid repeated construction
394     IntType const zero(0);
395 
396     if (i == zero) throw bad_rational();
397     if (num == zero) return *this;
398 
399     // Avoid overflow and preserve normalization
400     IntType const gcd = integer::gcd(num, i);
401     num /= gcd;
402     den *= i / gcd;
403 
404     if (den < zero) {
405         num = -num;
406         den = -den;
407     }
408 
409     return *this;
410 }
411 
412 // Comparison operators
413 template <typename IntType>
operator <(const rational<IntType> & r) const414 bool rational<IntType>::operator< (const rational<IntType>& r) const
415 {
416     // Avoid repeated construction
417     int_type const  zero( 0 );
418 
419     // This should really be a class-wide invariant.  The reason for these
420     // checks is that for 2's complement systems, INT_MIN has no corresponding
421     // positive, so negating it during normalization keeps it INT_MIN, which
422     // is bad for later calculations that assume a positive denominator.
423     BOOST_ASSERT( this->den > zero );
424     BOOST_ASSERT( r.den > zero );
425 
426     // Determine relative order by expanding each value to its simple continued
427     // fraction representation using the Euclidian GCD algorithm.
428     struct { int_type  n, d, q, r; }
429      ts = { this->num, this->den, static_cast<int_type>(this->num / this->den),
430      static_cast<int_type>(this->num % this->den) },
431      rs = { r.num, r.den, static_cast<int_type>(r.num / r.den),
432      static_cast<int_type>(r.num % r.den) };
433     unsigned  reverse = 0u;
434 
435     // Normalize negative moduli by repeatedly adding the (positive) denominator
436     // and decrementing the quotient.  Later cycles should have all positive
437     // values, so this only has to be done for the first cycle.  (The rules of
438     // C++ require a nonnegative quotient & remainder for a nonnegative dividend
439     // & positive divisor.)
440     while ( ts.r < zero )  { ts.r += ts.d; --ts.q; }
441     while ( rs.r < zero )  { rs.r += rs.d; --rs.q; }
442 
443     // Loop through and compare each variable's continued-fraction components
444     for ( ;; )
445     {
446         // The quotients of the current cycle are the continued-fraction
447         // components.  Comparing two c.f. is comparing their sequences,
448         // stopping at the first difference.
449         if ( ts.q != rs.q )
450         {
451             // Since reciprocation changes the relative order of two variables,
452             // and c.f. use reciprocals, the less/greater-than test reverses
453             // after each index.  (Start w/ non-reversed @ whole-number place.)
454             return reverse ? ts.q > rs.q : ts.q < rs.q;
455         }
456 
457         // Prepare the next cycle
458         reverse ^= 1u;
459 
460         if ( (ts.r == zero) || (rs.r == zero) )
461         {
462             // At least one variable's c.f. expansion has ended
463             break;
464         }
465 
466         ts.n = ts.d;         ts.d = ts.r;
467         ts.q = ts.n / ts.d;  ts.r = ts.n % ts.d;
468         rs.n = rs.d;         rs.d = rs.r;
469         rs.q = rs.n / rs.d;  rs.r = rs.n % rs.d;
470     }
471 
472     // Compare infinity-valued components for otherwise equal sequences
473     if ( ts.r == rs.r )
474     {
475         // Both remainders are zero, so the next (and subsequent) c.f.
476         // components for both sequences are infinity.  Therefore, the sequences
477         // and their corresponding values are equal.
478         return false;
479     }
480     else
481     {
482 #ifdef BOOST_MSVC
483 #pragma warning(push)
484 #pragma warning(disable:4800)
485 #endif
486         // Exactly one of the remainders is zero, so all following c.f.
487         // components of that variable are infinity, while the other variable
488         // has a finite next c.f. component.  So that other variable has the
489         // lesser value (modulo the reversal flag!).
490         return ( ts.r != zero ) != static_cast<bool>( reverse );
491 #ifdef BOOST_MSVC
492 #pragma warning(pop)
493 #endif
494     }
495 }
496 
497 template <typename IntType>
operator <(param_type i) const498 bool rational<IntType>::operator< (param_type i) const
499 {
500     // Avoid repeated construction
501     int_type const  zero( 0 );
502 
503     // Break value into mixed-fraction form, w/ always-nonnegative remainder
504     BOOST_ASSERT( this->den > zero );
505     int_type  q = this->num / this->den, r = this->num % this->den;
506     while ( r < zero )  { r += this->den; --q; }
507 
508     // Compare with just the quotient, since the remainder always bumps the
509     // value up.  [Since q = floor(n/d), and if n/d < i then q < i, if n/d == i
510     // then q == i, if n/d == i + r/d then q == i, and if n/d >= i + 1 then
511     // q >= i + 1 > i; therefore n/d < i iff q < i.]
512     return q < i;
513 }
514 
515 template <typename IntType>
operator >(param_type i) const516 bool rational<IntType>::operator> (param_type i) const
517 {
518     return operator==(i)? false: !operator<(i);
519 }
520 
521 template <typename IntType>
522 BOOST_CONSTEXPR
operator ==(const rational<IntType> & r) const523 inline bool rational<IntType>::operator== (const rational<IntType>& r) const
524 {
525     return ((num == r.num) && (den == r.den));
526 }
527 
528 template <typename IntType>
529 BOOST_CONSTEXPR
operator ==(param_type i) const530 inline bool rational<IntType>::operator== (param_type i) const
531 {
532     return ((den == IntType(1)) && (num == i));
533 }
534 
535 // Invariant check
536 template <typename IntType>
test_invariant() const537 inline bool rational<IntType>::test_invariant() const
538 {
539     return ( this->den > int_type(0) ) && ( integer::gcd(this->num, this->den) ==
540      int_type(1) );
541 }
542 
543 // Normalisation
544 template <typename IntType>
normalize()545 void rational<IntType>::normalize()
546 {
547     // Avoid repeated construction
548     IntType zero(0);
549 
550     if (den == zero)
551         throw bad_rational();
552 
553     // Handle the case of zero separately, to avoid division by zero
554     if (num == zero) {
555         den = IntType(1);
556         return;
557     }
558 
559     IntType g = integer::gcd(num, den);
560 
561     num /= g;
562     den /= g;
563 
564     // Ensure that the denominator is positive
565     if (den < zero) {
566         num = -num;
567         den = -den;
568     }
569 
570     // ...But acknowledge that the previous step doesn't always work.
571     // (Nominally, this should be done before the mutating steps, but this
572     // member function is only called during the constructor, so we never have
573     // to worry about zombie objects.)
574     if (den < zero)
575         throw bad_rational( "bad rational: non-zero singular denominator" );
576 
577     BOOST_ASSERT( this->test_invariant() );
578 }
579 
580 #ifndef BOOST_NO_IOSTREAM
581 namespace detail {
582 
583     // A utility class to reset the format flags for an istream at end
584     // of scope, even in case of exceptions
585     struct resetter {
resetterboost::detail::resetter586         resetter(std::istream& is) : is_(is), f_(is.flags()) {}
~resetterboost::detail::resetter587         ~resetter() { is_.flags(f_); }
588         std::istream& is_;
589         std::istream::fmtflags f_;      // old GNU c++ lib has no ios_base
590     };
591 
592 }
593 
594 // Input and output
595 template <typename IntType>
operator >>(std::istream & is,rational<IntType> & r)596 std::istream& operator>> (std::istream& is, rational<IntType>& r)
597 {
598     using std::ios;
599 
600     IntType n = IntType(0), d = IntType(1);
601     char c = 0;
602     detail::resetter sentry(is);
603 
604     if ( is >> n )
605     {
606         if ( is.get(c) )
607         {
608             if ( c == '/' )
609             {
610                 if ( is >> std::noskipws >> d )
611                     try {
612                         r.assign( n, d );
613                     } catch ( bad_rational & ) {        // normalization fail
614                         try { is.setstate(ios::failbit); }
615                         catch ( ... ) {}  // don't throw ios_base::failure...
616                         if ( is.exceptions() & ios::failbit )
617                             throw;   // ...but the original exception instead
618                         // ELSE: suppress the exception, use just error flags
619                     }
620             }
621             else
622                 is.setstate( ios::failbit );
623         }
624     }
625 
626     return is;
627 }
628 
629 // Add manipulators for output format?
630 template <typename IntType>
operator <<(std::ostream & os,const rational<IntType> & r)631 std::ostream& operator<< (std::ostream& os, const rational<IntType>& r)
632 {
633     using namespace std;
634 
635     // The slash directly precedes the denominator, which has no prefixes.
636     ostringstream  ss;
637 
638     ss.copyfmt( os );
639     ss.tie( NULL );
640     ss.exceptions( ios::goodbit );
641     ss.width( 0 );
642     ss << noshowpos << noshowbase << '/' << r.denominator();
643 
644     // The numerator holds the showpos, internal, and showbase flags.
645     string const   tail = ss.str();
646     streamsize const  w = os.width() - static_cast<streamsize>( tail.size() );
647 
648     ss.clear();
649     ss.str( "" );
650     ss.flags( os.flags() );
651     ss << setw( w < 0 || (os.flags() & ios::adjustfield) != ios::internal ? 0 :
652      w ) << r.numerator();
653     return os << ss.str() + tail;
654 }
655 #endif  // BOOST_NO_IOSTREAM
656 
657 // Type conversion
658 template <typename T, typename IntType>
659 BOOST_CONSTEXPR
rational_cast(const rational<IntType> & src)660 inline T rational_cast(const rational<IntType>& src)
661 {
662     return static_cast<T>(src.numerator())/static_cast<T>(src.denominator());
663 }
664 
665 // Do not use any abs() defined on IntType - it isn't worth it, given the
666 // difficulties involved (Koenig lookup required, there may not *be* an abs()
667 // defined, etc etc).
668 template <typename IntType>
abs(const rational<IntType> & r)669 inline rational<IntType> abs(const rational<IntType>& r)
670 {
671     return r.numerator() >= IntType(0)? r: -r;
672 }
673 
674 } // namespace boost
675 
676 #endif  // BOOST_RATIONAL_HPP
677 
678