annotate DEPENDENCIES/generic/include/boost/rational.hpp @ 125:34e428693f5d vext

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