rational.hpp 23 KB

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