1/*
2 * A test program for boost/rational.hpp.
3 * Change the typedef at the beginning of run_tests() to try out different
4 * integer types. (These tests are designed only for signed integer
5 * types. They should work for short, int and long.)
6 *
7 * (C) Copyright Stephen Silver, 2001. Permission to copy, use, modify, sell
8 * and distribute this software is granted provided this copyright notice
9 * appears in all copies. This software is provided "as is" without express or
10 * implied warranty, and with no claim as to its suitability for any purpose.
11 *
12 * Incorporated into the boost rational number library, and modified and
13 * extended, by Paul Moore, with permission.
14 */
15
16// boostinspect:nolicense (don't complain about the lack of a Boost license)
17// (Stephen Silver hasn't been contacted yet for permission to change the
18// license. If Paul Moore's permission is also needed, then that's a problem
19// since he hasn't been in contact for years.)
20
21// Revision History
22// 30 Aug 13 Add bug-test of assignments holding the basic and/or strong
23// guarantees (Daryle Walker)
24// 27 Aug 13 Add test for cross-version constructor template (Daryle Walker)
25// 23 Aug 13 Add bug-test of narrowing conversions during order comparison;
26// spell logical-negation in it as "!" because MSVC won't accept
27// "not" (Daryle Walker)
28// 05 Nov 06 Add testing of zero-valued denominators & divisors; casting with
29// types that are not implicitly convertible (Daryle Walker)
30// 04 Nov 06 Resolve GCD issue with depreciation (Daryle Walker)
31// 02 Nov 06 Add testing for operator<(int_type) w/ unsigneds (Daryle Walker)
32// 31 Oct 06 Add testing for operator<(rational) overflow (Daryle Walker)
33// 18 Oct 06 Various fixes for old compilers (Joaquín M López Muñoz)
34// 27 Dec 05 Add testing for Boolean conversion operator (Daryle Walker)
35// 24 Dec 05 Change code to use Boost.Test (Daryle Walker)
36// 04 Mar 01 Patches for Intel C++ and GCC (David Abrahams)
37
38#define BOOST_TEST_MAIN "Boost::Rational unit tests"
39
40#include <boost/config.hpp>
41#include <boost/limits.hpp>
42#include <boost/mpl/list.hpp>
43#include <boost/operators.hpp>
44#include <boost/preprocessor/stringize.hpp>
45#include <boost/integer/common_factor_rt.hpp>
46#include <boost/cstdint.hpp>
47
48#include <boost/rational.hpp>
49
50#include <boost/test/unit_test.hpp>
51
52#include <climits>
53#include <iomanip>
54#include <ios>
55#include <iostream>
56#include <istream>
57#include <ostream>
58#include <sstream>
59#include <stdexcept>
60#include <string>
61
62#ifdef _MSC_VER
63#pragma warning(disable:4146)
64#endif
65
66
67// We can override this on the compile, as -DINT_TYPE=short or whatever.
68// The default test is against rational<long>.
69#ifndef INT_TYPE
70#define INT_TYPE long
71#endif
72
73namespace {
74
75class MyOverflowingUnsigned;
76
77// This is a trivial user-defined wrapper around the built in int type.
78// It can be used as a test type for rational<>
79class MyInt : boost::operators<MyInt>
80{
81 friend class MyOverflowingUnsigned;
82 int val;
83public:
84 MyInt(int n = 0) : val(n) {}
85 friend MyInt operator+ (const MyInt&);
86 friend MyInt operator- (const MyInt&);
87 MyInt& operator+= (const MyInt& rhs) { val += rhs.val; return *this; }
88 MyInt& operator-= (const MyInt& rhs) { val -= rhs.val; return *this; }
89 MyInt& operator*= (const MyInt& rhs) { val *= rhs.val; return *this; }
90 MyInt& operator/= (const MyInt& rhs) { val /= rhs.val; return *this; }
91 MyInt& operator%= (const MyInt& rhs) { val %= rhs.val; return *this; }
92 MyInt& operator|= (const MyInt& rhs) { val |= rhs.val; return *this; }
93 MyInt& operator&= (const MyInt& rhs) { val &= rhs.val; return *this; }
94 MyInt& operator^= (const MyInt& rhs) { val ^= rhs.val; return *this; }
95 const MyInt& operator++() { ++val; return *this; }
96 const MyInt& operator--() { --val; return *this; }
97 bool operator< (const MyInt& rhs) const { return val < rhs.val; }
98 bool operator== (const MyInt& rhs) const { return val == rhs.val; }
99 bool operator! () const { return !val; }
100 friend std::istream& operator>>(std::istream&, MyInt&);
101 friend std::ostream& operator<<(std::ostream&, const MyInt&);
102};
103
104inline MyInt operator+(const MyInt& rhs) { return rhs; }
105inline MyInt operator-(const MyInt& rhs) { return MyInt(-rhs.val); }
106inline std::istream& operator>>(std::istream& is, MyInt& i) { is >> i.val; return is; }
107inline std::ostream& operator<<(std::ostream& os, const MyInt& i) { os << i.val; return os; }
108inline MyInt abs(MyInt rhs) { if (rhs < MyInt()) rhs = -rhs; return rhs; }
109
110// This is an "unsigned" wrapper, that throws on overflow. It can be used to
111// test rational<> when an operation goes out of bounds.
112class MyOverflowingUnsigned
113 : private boost::unit_steppable<MyOverflowingUnsigned>
114 , private boost::ordered_euclidian_ring_operators1<MyOverflowingUnsigned>
115{
116 // Helper type-aliases
117 typedef MyOverflowingUnsigned self_type;
118 typedef unsigned self_type::* bool_type;
119
120 // Member data
121 unsigned v_;
122
123public:
124 // Exception base class
125 class exception_base { protected: virtual ~exception_base() throw() {} };
126
127 // Divide-by-zero exception class
128 class divide_by_0_error
129 : public virtual exception_base
130 , public std::domain_error
131 {
132 public:
133 explicit divide_by_0_error( std::string const &w )
134 : std::domain_error( w ) {}
135
136 virtual ~divide_by_0_error() throw() {}
137 };
138
139 // Overflow exception class
140 class overflowing_error
141 : public virtual exception_base
142 , public std::overflow_error
143 {
144 public:
145 explicit overflowing_error( std::string const &w )
146 : std::overflow_error( w ) {}
147
148 virtual ~overflowing_error() throw() {}
149 };
150
151 // Lifetime management (use automatic dtr & copy-ctr)
152 MyOverflowingUnsigned( unsigned v = 0 ) : v_( v ) {}
153 explicit MyOverflowingUnsigned( MyInt const &m ) : v_( m.val ) {}
154
155 // Operators (use automatic copy-assignment); arithmetic & comparison only
156 self_type & operator ++()
157 {
158 if ( this->v_ == UINT_MAX ) throw overflowing_error( "increment" );
159 else ++this->v_;
160 return *this;
161 }
162 self_type & operator --()
163 {
164 if ( !this->v_ ) throw overflowing_error( "decrement" );
165 else --this->v_;
166 return *this;
167 }
168
169 operator bool_type() const { return this->v_ ? &self_type::v_ : 0; }
170
171 bool operator !() const { return !this->v_; }
172 self_type operator +() const { return self_type( +this->v_ ); }
173 self_type operator -() const { return self_type( -this->v_ ); }
174
175 bool operator <(self_type const &r) const { return this->v_ < r.v_; }
176 bool operator ==(self_type const &r) const { return this->v_ == r.v_; }
177
178 self_type & operator *=( self_type const &r )
179 {
180 if ( r.v_ && this->v_ > UINT_MAX / r.v_ )
181 {
182 throw overflowing_error( "oversized factors" );
183 }
184 this->v_ *= r.v_;
185 return *this;
186 }
187 self_type & operator /=( self_type const &r )
188 {
189 if ( !r.v_ ) throw divide_by_0_error( "division" );
190 this->v_ /= r.v_;
191 return *this;
192 }
193 self_type & operator %=( self_type const &r )
194 {
195 if ( !r.v_ ) throw divide_by_0_error( "modulus" );
196 this->v_ %= r.v_;
197 return *this;
198 }
199 self_type & operator +=( self_type const &r )
200 {
201 if ( this->v_ > UINT_MAX - r.v_ )
202 {
203 throw overflowing_error( "oversized addends" );
204 }
205 this->v_ += r.v_;
206 return *this;
207 }
208 self_type & operator -=( self_type const &r )
209 {
210 if ( this->v_ < r.v_ )
211 {
212 throw overflowing_error( "oversized subtrahend" );
213 }
214 this->v_ -= r.v_;
215 return *this;
216 }
217
218 // Input & output
219 template < typename Ch, class Tr >
220 friend std::basic_istream<Ch, Tr> &
221 operator >>( std::basic_istream<Ch, Tr> &i, self_type &x )
222 { return i >> x.v_; }
223
224 template < typename Ch, class Tr >
225 friend std::basic_ostream<Ch, Tr> &
226 operator <<( std::basic_ostream<Ch, Tr> &o, self_type const &x )
227 { return o << x.v_; }
228
229}; // MyOverflowingUnsigned
230
231inline MyOverflowingUnsigned abs( MyOverflowingUnsigned const &x ) { return x; }
232
233} // namespace
234
235
236// Specialize numeric_limits for the custom types
237namespace std
238{
239
240template < >
241class numeric_limits< MyInt >
242{
243 typedef numeric_limits<int> limits_type;
244
245public:
246 static const bool is_specialized = limits_type::is_specialized;
247
248 static MyInt min BOOST_PREVENT_MACRO_SUBSTITUTION () throw() { return
249 limits_type::min BOOST_PREVENT_MACRO_SUBSTITUTION (); }
250 static MyInt max BOOST_PREVENT_MACRO_SUBSTITUTION () throw() { return
251 limits_type::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
252 static MyInt lowest() throw() { return min BOOST_PREVENT_MACRO_SUBSTITUTION
253 (); } // C++11
254
255 static const int digits = limits_type::digits;
256 static const int digits10 = limits_type::digits10;
257 static const int max_digits10 = 0; // C++11
258 static const bool is_signed = limits_type::is_signed;
259 static const bool is_integer = limits_type::is_integer;
260 static const bool is_exact = limits_type::is_exact;
261 static const int radix = limits_type::radix;
262 static MyInt epsilon() throw() { return limits_type::epsilon(); }
263 static MyInt round_error() throw() { return limits_type::round_error(); }
264
265 static const int min_exponent = limits_type::min_exponent;
266 static const int min_exponent10 = limits_type::min_exponent10;
267 static const int max_exponent = limits_type::max_exponent;
268 static const int max_exponent10 = limits_type::max_exponent10;
269
270 static const bool has_infinity = limits_type::has_infinity;
271 static const bool has_quiet_NaN = limits_type::has_quiet_NaN;
272 static const bool has_signaling_NaN = limits_type::has_signaling_NaN;
273 static const float_denorm_style has_denorm = limits_type::has_denorm;
274 static const bool has_denorm_loss = limits_type::has_denorm_loss;
275
276 static MyInt infinity() throw() { return limits_type::infinity(); }
277 static MyInt quiet_NaN() throw() { return limits_type::quiet_NaN(); }
278 static MyInt signaling_NaN() throw() {return limits_type::signaling_NaN();}
279 static MyInt denorm_min() throw() { return limits_type::denorm_min(); }
280
281 static const bool is_iec559 = limits_type::is_iec559;
282 static const bool is_bounded = limits_type::is_bounded;
283 static const bool is_modulo = limits_type::is_modulo;
284
285 static const bool traps = limits_type::traps;
286 static const bool tinyness_before = limits_type::tinyness_before;
287 static const float_round_style round_style = limits_type::round_style;
288
289}; // std::numeric_limits<MyInt>
290
291template < >
292class numeric_limits< MyOverflowingUnsigned >
293{
294 typedef numeric_limits<unsigned> limits_type;
295
296public:
297 static const bool is_specialized = limits_type::is_specialized;
298
299 static MyOverflowingUnsigned min BOOST_PREVENT_MACRO_SUBSTITUTION () throw()
300 { return limits_type::min BOOST_PREVENT_MACRO_SUBSTITUTION (); }
301 static MyOverflowingUnsigned max BOOST_PREVENT_MACRO_SUBSTITUTION () throw()
302 { return limits_type::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
303 static MyOverflowingUnsigned lowest() throw()
304 { return min BOOST_PREVENT_MACRO_SUBSTITUTION (); } // C++11
305
306 static const int digits = limits_type::digits;
307 static const int digits10 = limits_type::digits10;
308 static const int max_digits10 = 0; // C++11
309 static const bool is_signed = limits_type::is_signed;
310 static const bool is_integer = limits_type::is_integer;
311 static const bool is_exact = limits_type::is_exact;
312 static const int radix = limits_type::radix;
313 static MyOverflowingUnsigned epsilon() throw()
314 { return limits_type::epsilon(); }
315 static MyOverflowingUnsigned round_error() throw()
316 {return limits_type::round_error();}
317
318 static const int min_exponent = limits_type::min_exponent;
319 static const int min_exponent10 = limits_type::min_exponent10;
320 static const int max_exponent = limits_type::max_exponent;
321 static const int max_exponent10 = limits_type::max_exponent10;
322
323 static const bool has_infinity = limits_type::has_infinity;
324 static const bool has_quiet_NaN = limits_type::has_quiet_NaN;
325 static const bool has_signaling_NaN = limits_type::has_signaling_NaN;
326 static const float_denorm_style has_denorm = limits_type::has_denorm;
327 static const bool has_denorm_loss = limits_type::has_denorm_loss;
328
329 static MyOverflowingUnsigned infinity() throw()
330 { return limits_type::infinity(); }
331 static MyOverflowingUnsigned quiet_NaN() throw()
332 { return limits_type::quiet_NaN(); }
333 static MyOverflowingUnsigned signaling_NaN() throw()
334 { return limits_type::signaling_NaN(); }
335 static MyOverflowingUnsigned denorm_min() throw()
336 { return limits_type::denorm_min(); }
337
338 static const bool is_iec559 = limits_type::is_iec559;
339 static const bool is_bounded = limits_type::is_bounded;
340 static const bool is_modulo = limits_type::is_modulo;
341
342 static const bool traps = limits_type::traps;
343 static const bool tinyness_before = limits_type::tinyness_before;
344 static const float_round_style round_style = limits_type::round_style;
345
346}; // std::numeric_limits<MyOverflowingUnsigned>
347
348} // namespace std
349
350
351namespace {
352
353// This fixture replaces the check of rational's packing at the start of main.
354class rational_size_check
355{
356 typedef INT_TYPE int_type;
357 typedef ::boost::rational<int_type> rational_type;
358
359public:
360 rational_size_check()
361 {
362 using ::std::cout;
363
364 char const * const int_name = BOOST_PP_STRINGIZE( INT_TYPE );
365
366 cout << "Running tests for boost::rational<" << int_name << ">\n\n";
367
368 cout << "Implementation issue: the minimal size for a rational\n"
369 << "is twice the size of the underlying integer type.\n\n";
370
371 cout << "Checking to see if space is being wasted.\n"
372 << "\tsizeof(" << int_name << ") == " << sizeof( int_type )
373 << "\n";
374 cout << "\tsizeof(boost::rational<" << int_name << ">) == "
375 << sizeof( rational_type ) << "\n\n";
376
377 cout << "Implementation has "
378 << (
379 (sizeof( rational_type ) > 2u * sizeof( int_type ))
380 ? "included padding bytes"
381 : "minimal size"
382 )
383 << "\n\n";
384 }
385};
386
387// This fixture groups all the common settings.
388class my_configuration
389{
390public:
391 template < typename T >
392 class hook
393 {
394 public:
395 typedef ::boost::rational<T> rational_type;
396
397 private:
398 struct parts { rational_type parts_[ 9 ]; };
399
400 static parts generate_rationals()
401 {
402 rational_type r1, r2( 0 ), r3( 1 ), r4( -3 ), r5( 7, 2 ),
403 r6( 5, 15 ), r7( 14, -21 ), r8( -4, 6 ),
404 r9( -14, -70 );
405 parts result;
406 result.parts_[0] = r1;
407 result.parts_[1] = r2;
408 result.parts_[2] = r3;
409 result.parts_[3] = r4;
410 result.parts_[4] = r5;
411 result.parts_[5] = r6;
412 result.parts_[6] = r7;
413 result.parts_[7] = r8;
414 result.parts_[8] = r9;
415
416 return result;
417 }
418
419 parts p_; // Order Dependency
420
421 public:
422 rational_type ( &r_ )[ 9 ]; // Order Dependency
423
424 hook() : p_( generate_rationals() ), r_( p_.parts_ ) {}
425 };
426};
427
428// Instead of controlling the integer type needed with a #define, use a list of
429// all available types. Since the headers #included don't change because of the
430// integer #define, only the built-in types and MyInt are available. (Any other
431// arbitrary integer type introduced by the #define would get compiler errors
432// because its header can't be #included.)
433typedef ::boost::mpl::list<short, int, long> builtin_signed_test_types;
434typedef ::boost::mpl::list<short, int, long, MyInt> all_signed_test_types;
435
436// Without these explicit instantiations, MSVC++ 6.5/7.0 does not find
437// some friend operators in certain contexts.
438::boost::rational<short> dummy1;
439::boost::rational<int> dummy2;
440::boost::rational<long> dummy3;
441::boost::rational<MyInt> dummy4;
442::boost::rational<MyOverflowingUnsigned> dummy5;
443::boost::rational<unsigned> dummy6;
444
445// Should there be regular tests with unsigned integer types?
446
447} // namespace
448
449
450// Check if rational is the smallest size possible
451BOOST_GLOBAL_FIXTURE( rational_size_check );
452
453
454#if BOOST_CONTROL_RATIONAL_HAS_GCD
455// The factoring function template suite
456BOOST_AUTO_TEST_SUITE( factoring_suite )
457
458// GCD tests
459BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_test, T, all_signed_test_types )
460{
461 BOOST_CHECK_EQUAL( boost::gcd<T>( 1, -1), static_cast<T>( 1) );
462 BOOST_CHECK_EQUAL( boost::gcd<T>( -1, 1), static_cast<T>( 1) );
463 BOOST_CHECK_EQUAL( boost::gcd<T>( 1, 1), static_cast<T>( 1) );
464 BOOST_CHECK_EQUAL( boost::gcd<T>( -1, -1), static_cast<T>( 1) );
465 BOOST_CHECK_EQUAL( boost::gcd<T>( 0, 0), static_cast<T>( 0) );
466 BOOST_CHECK_EQUAL( boost::gcd<T>( 7, 0), static_cast<T>( 7) );
467 BOOST_CHECK_EQUAL( boost::gcd<T>( 0, 9), static_cast<T>( 9) );
468 BOOST_CHECK_EQUAL( boost::gcd<T>( -7, 0), static_cast<T>( 7) );
469 BOOST_CHECK_EQUAL( boost::gcd<T>( 0, -9), static_cast<T>( 9) );
470 BOOST_CHECK_EQUAL( boost::gcd<T>( 42, 30), static_cast<T>( 6) );
471 BOOST_CHECK_EQUAL( boost::gcd<T>( 6, -9), static_cast<T>( 3) );
472 BOOST_CHECK_EQUAL( boost::gcd<T>(-10, -10), static_cast<T>(10) );
473 BOOST_CHECK_EQUAL( boost::gcd<T>(-25, -10), static_cast<T>( 5) );
474}
475
476// LCM tests
477BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_test, T, all_signed_test_types )
478{
479 BOOST_CHECK_EQUAL( boost::lcm<T>( 1, -1), static_cast<T>( 1) );
480 BOOST_CHECK_EQUAL( boost::lcm<T>( -1, 1), static_cast<T>( 1) );
481 BOOST_CHECK_EQUAL( boost::lcm<T>( 1, 1), static_cast<T>( 1) );
482 BOOST_CHECK_EQUAL( boost::lcm<T>( -1, -1), static_cast<T>( 1) );
483 BOOST_CHECK_EQUAL( boost::lcm<T>( 0, 0), static_cast<T>( 0) );
484 BOOST_CHECK_EQUAL( boost::lcm<T>( 6, 0), static_cast<T>( 0) );
485 BOOST_CHECK_EQUAL( boost::lcm<T>( 0, 7), static_cast<T>( 0) );
486 BOOST_CHECK_EQUAL( boost::lcm<T>( -5, 0), static_cast<T>( 0) );
487 BOOST_CHECK_EQUAL( boost::lcm<T>( 0, -4), static_cast<T>( 0) );
488 BOOST_CHECK_EQUAL( boost::lcm<T>( 18, 30), static_cast<T>(90) );
489 BOOST_CHECK_EQUAL( boost::lcm<T>( -6, 9), static_cast<T>(18) );
490 BOOST_CHECK_EQUAL( boost::lcm<T>(-10, -10), static_cast<T>(10) );
491 BOOST_CHECK_EQUAL( boost::lcm<T>( 25, -10), static_cast<T>(50) );
492}
493
494BOOST_AUTO_TEST_SUITE_END()
495#endif // BOOST_CONTROL_RATIONAL_HAS_GCD
496
497
498// The basic test suite
499BOOST_FIXTURE_TEST_SUITE( basic_rational_suite, my_configuration )
500
501// Initialization tests
502BOOST_AUTO_TEST_CASE_TEMPLATE( rational_initialization_test, T,
503 all_signed_test_types )
504{
505 my_configuration::hook<T> h;
506 boost::rational<T> &r1 = h.r_[ 0 ], &r2 = h.r_[ 1 ], &r3 = h.r_[ 2 ],
507 &r4 = h.r_[ 3 ], &r5 = h.r_[ 4 ], &r6 = h.r_[ 5 ],
508 &r7 = h.r_[ 6 ], &r8 = h.r_[ 7 ], &r9 = h.r_[ 8 ];
509
510 BOOST_CHECK_EQUAL( r1.numerator(), static_cast<T>( 0) );
511 BOOST_CHECK_EQUAL( r2.numerator(), static_cast<T>( 0) );
512 BOOST_CHECK_EQUAL( r3.numerator(), static_cast<T>( 1) );
513 BOOST_CHECK_EQUAL( r4.numerator(), static_cast<T>(-3) );
514 BOOST_CHECK_EQUAL( r5.numerator(), static_cast<T>( 7) );
515 BOOST_CHECK_EQUAL( r6.numerator(), static_cast<T>( 1) );
516 BOOST_CHECK_EQUAL( r7.numerator(), static_cast<T>(-2) );
517 BOOST_CHECK_EQUAL( r8.numerator(), static_cast<T>(-2) );
518 BOOST_CHECK_EQUAL( r9.numerator(), static_cast<T>( 1) );
519
520 BOOST_CHECK_EQUAL( r1.denominator(), static_cast<T>(1) );
521 BOOST_CHECK_EQUAL( r2.denominator(), static_cast<T>(1) );
522 BOOST_CHECK_EQUAL( r3.denominator(), static_cast<T>(1) );
523 BOOST_CHECK_EQUAL( r4.denominator(), static_cast<T>(1) );
524 BOOST_CHECK_EQUAL( r5.denominator(), static_cast<T>(2) );
525 BOOST_CHECK_EQUAL( r6.denominator(), static_cast<T>(3) );
526 BOOST_CHECK_EQUAL( r7.denominator(), static_cast<T>(3) );
527 BOOST_CHECK_EQUAL( r8.denominator(), static_cast<T>(3) );
528 BOOST_CHECK_EQUAL( r9.denominator(), static_cast<T>(5) );
529
530 BOOST_CHECK_THROW( boost::rational<T>( 3, 0), boost::bad_rational );
531 BOOST_CHECK_THROW( boost::rational<T>(-2, 0), boost::bad_rational );
532 BOOST_CHECK_THROW( boost::rational<T>( 0, 0), boost::bad_rational );
533}
534
535// Assignment (non-operator) tests
536BOOST_AUTO_TEST_CASE_TEMPLATE( rational_assign_test, T, all_signed_test_types )
537{
538 my_configuration::hook<T> h;
539 boost::rational<T> & r = h.r_[ 0 ];
540
541 r.assign( 6, 8 );
542 BOOST_CHECK_EQUAL( r.numerator(), static_cast<T>(3) );
543 BOOST_CHECK_EQUAL( r.denominator(), static_cast<T>(4) );
544
545 r.assign( 0, -7 );
546 BOOST_CHECK_EQUAL( r.numerator(), static_cast<T>(0) );
547 BOOST_CHECK_EQUAL( r.denominator(), static_cast<T>(1) );
548
549 BOOST_CHECK_THROW( r.assign( 4, 0), boost::bad_rational );
550 BOOST_CHECK_THROW( r.assign( 0, 0), boost::bad_rational );
551 BOOST_CHECK_THROW( r.assign(-7, 0), boost::bad_rational );
552}
553
554// Comparison tests
555BOOST_AUTO_TEST_CASE_TEMPLATE( rational_comparison_test, T,
556 all_signed_test_types )
557{
558 my_configuration::hook<T> h;
559 const boost::rational<T> &r1 = h.r_[ 0 ], &r2 = h.r_[ 1 ], &r3 = h.r_[ 2 ],
560 &r4 = h.r_[ 3 ], &r5 = h.r_[ 4 ], &r6 = h.r_[ 5 ],
561 &r7 = h.r_[ 6 ], &r8 = h.r_[ 7 ], &r9 = h.r_[ 8 ];
562
563 BOOST_CHECK( r1 == r2 );
564 BOOST_CHECK( r2 != r3 );
565 BOOST_CHECK( r4 < r3 );
566 BOOST_CHECK( r4 <= r5 );
567 BOOST_CHECK( r1 <= r2 );
568 BOOST_CHECK( r5 > r6 );
569 BOOST_CHECK( r5 >= r6 );
570 BOOST_CHECK( r7 >= r8 );
571
572 BOOST_CHECK( !(r3 == r2) );
573 BOOST_CHECK( !(r1 != r2) );
574 BOOST_CHECK( !(r1 < r2) );
575 BOOST_CHECK( !(r5 < r6) );
576 BOOST_CHECK( !(r9 <= r2) );
577 BOOST_CHECK( !(r8 > r7) );
578 BOOST_CHECK( !(r8 > r2) );
579 BOOST_CHECK( !(r4 >= r6) );
580
581 BOOST_CHECK( r1 == static_cast<T>( 0) );
582 BOOST_CHECK( r2 != static_cast<T>(-1) );
583 BOOST_CHECK( r3 < static_cast<T>( 2) );
584 BOOST_CHECK( r4 <= static_cast<T>(-3) );
585 BOOST_CHECK( r5 > static_cast<T>( 3) );
586 BOOST_CHECK( r6 >= static_cast<T>( 0) );
587
588 BOOST_CHECK( static_cast<T>( 0) == r2 );
589 BOOST_CHECK( static_cast<T>( 0) != r7 );
590 BOOST_CHECK( static_cast<T>(-1) < r8 );
591 BOOST_CHECK( static_cast<T>(-2) <= r9 );
592 BOOST_CHECK( static_cast<T>( 1) > r1 );
593 BOOST_CHECK( static_cast<T>( 1) >= r3 );
594
595 // Extra tests with values close in continued-fraction notation
596 boost::rational<T> const x1( static_cast<T>(9), static_cast<T>(4) );
597 boost::rational<T> const x2( static_cast<T>(61), static_cast<T>(27) );
598 boost::rational<T> const x3( static_cast<T>(52), static_cast<T>(23) );
599 boost::rational<T> const x4( static_cast<T>(70), static_cast<T>(31) );
600
601 BOOST_CHECK( x1 < x2 );
602 BOOST_CHECK( !(x1 < x1) );
603 BOOST_CHECK( !(x2 < x2) );
604 BOOST_CHECK( !(x2 < x1) );
605 BOOST_CHECK( x2 < x3 );
606 BOOST_CHECK( x4 < x2 );
607 BOOST_CHECK( !(x3 < x4) );
608 BOOST_CHECK( r7 < x1 ); // not actually close; wanted -ve v. +ve instead
609 BOOST_CHECK( !(x2 < r7) );
610}
611
612// Increment & decrement tests
613BOOST_AUTO_TEST_CASE_TEMPLATE( rational_1step_test, T, all_signed_test_types )
614{
615 my_configuration::hook<T> h;
616 boost::rational<T> &r1 = h.r_[ 0 ], &r2 = h.r_[ 1 ], &r3 = h.r_[ 2 ],
617 &r7 = h.r_[ 6 ], &r8 = h.r_[ 7 ];
618
619 BOOST_CHECK( r1++ == r2 );
620 BOOST_CHECK( r1 != r2 );
621 BOOST_CHECK( r1 == r3 );
622 BOOST_CHECK( --r1 == r2 );
623 BOOST_CHECK( r8-- == r7 );
624 BOOST_CHECK( r8 != r7 );
625 BOOST_CHECK( ++r8 == r7 );
626}
627
628// Absolute value tests
629BOOST_AUTO_TEST_CASE_TEMPLATE( rational_abs_test, T, all_signed_test_types )
630{
631 typedef my_configuration::hook<T> hook_type;
632 typedef typename hook_type::rational_type rational_type;
633
634 hook_type h;
635 rational_type &r2 = h.r_[ 1 ], &r5 = h.r_[ 4 ], &r8 = h.r_[ 7 ];
636
637#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
638 // This is a nasty hack, required because some compilers do not implement
639 // "Koenig Lookup." Basically, if I call abs(r), the C++ standard says that
640 // the compiler should look for a definition of abs in the namespace which
641 // contains r's class (in this case boost)--among other places.
642
643 using boost::abs;
644#endif
645
646 BOOST_CHECK_EQUAL( abs(r2), r2 );
647 BOOST_CHECK_EQUAL( abs(r5), r5 );
648 BOOST_CHECK_EQUAL( abs(r8), rational_type(2, 3) );
649}
650
651// Unary operator tests
652BOOST_AUTO_TEST_CASE_TEMPLATE( rational_unary_test, T, all_signed_test_types )
653{
654 my_configuration::hook<T> h;
655 boost::rational<T> &r2 = h.r_[ 1 ], &r3 = h.r_[ 2 ],
656 &r4 = h.r_[ 3 ], &r5 = h.r_[ 4 ];
657
658 BOOST_CHECK_EQUAL( +r5, r5 );
659
660 BOOST_CHECK( -r3 != r3 );
661 BOOST_CHECK_EQUAL( -(-r3), r3 );
662 BOOST_CHECK_EQUAL( -r4, static_cast<T>(3) );
663
664 BOOST_CHECK( !r2 );
665 BOOST_CHECK( !!r3 );
666
667 BOOST_CHECK( ! static_cast<bool>(r2) );
668 BOOST_CHECK( r3 );
669}
670
671BOOST_AUTO_TEST_SUITE_END()
672
673
674// The rational arithmetic operations suite
675BOOST_AUTO_TEST_SUITE( rational_arithmetic_suite )
676
677// Addition & subtraction tests
678BOOST_AUTO_TEST_CASE_TEMPLATE( rational_additive_test, T,
679 all_signed_test_types )
680{
681 typedef boost::rational<T> rational_type;
682
683 BOOST_CHECK_EQUAL( rational_type( 1, 2) + rational_type(1, 2),
684 static_cast<T>(1) );
685 BOOST_CHECK_EQUAL( rational_type(11, 3) + rational_type(1, 2),
686 rational_type( 25, 6) );
687 BOOST_CHECK_EQUAL( rational_type(-8, 3) + rational_type(1, 5),
688 rational_type(-37, 15) );
689 BOOST_CHECK_EQUAL( rational_type(-7, 6) + rational_type(1, 7),
690 rational_type( 1, 7) - rational_type(7, 6) );
691 BOOST_CHECK_EQUAL( rational_type(13, 5) - rational_type(1, 2),
692 rational_type( 21, 10) );
693 BOOST_CHECK_EQUAL( rational_type(22, 3) + static_cast<T>(1),
694 rational_type( 25, 3) );
695 BOOST_CHECK_EQUAL( rational_type(12, 7) - static_cast<T>(2),
696 rational_type( -2, 7) );
697 BOOST_CHECK_EQUAL( static_cast<T>(3) + rational_type(4, 5),
698 rational_type( 19, 5) );
699 BOOST_CHECK_EQUAL( static_cast<T>(4) - rational_type(9, 2),
700 rational_type( -1, 2) );
701
702 rational_type r( 11 );
703
704 r -= rational_type( 20, 3 );
705 BOOST_CHECK_EQUAL( r, rational_type(13, 3) );
706
707 r += rational_type( 1, 2 );
708 BOOST_CHECK_EQUAL( r, rational_type(29, 6) );
709
710 r -= static_cast<T>( 5 );
711 BOOST_CHECK_EQUAL( r, rational_type( 1, -6) );
712
713 r += rational_type( 1, 5 );
714 BOOST_CHECK_EQUAL( r, rational_type( 1, 30) );
715
716 r += static_cast<T>( 2 );
717 BOOST_CHECK_EQUAL( r, rational_type(61, 30) );
718}
719
720// Assignment tests
721BOOST_AUTO_TEST_CASE_TEMPLATE( rational_assignment_test, T,
722 all_signed_test_types )
723{
724 typedef boost::rational<T> rational_type;
725
726 rational_type r;
727
728 r = rational_type( 1, 10 );
729 BOOST_CHECK_EQUAL( r, rational_type( 1, 10) );
730
731 r = static_cast<T>( -9 );
732 BOOST_CHECK_EQUAL( r, rational_type(-9, 1) );
733}
734
735// Multiplication tests
736BOOST_AUTO_TEST_CASE_TEMPLATE( rational_multiplication_test, T,
737 all_signed_test_types )
738{
739 typedef boost::rational<T> rational_type;
740
741 BOOST_CHECK_EQUAL( rational_type(1, 3) * rational_type(-3, 4),
742 rational_type(-1, 4) );
743 BOOST_CHECK_EQUAL( rational_type(2, 5) * static_cast<T>(7),
744 rational_type(14, 5) );
745 BOOST_CHECK_EQUAL( static_cast<T>(-2) * rational_type(1, 6),
746 rational_type(-1, 3) );
747
748 rational_type r = rational_type( 3, 7 );
749
750 r *= static_cast<T>( 14 );
751 BOOST_CHECK_EQUAL( r, static_cast<T>(6) );
752
753 r *= rational_type( 3, 8 );
754 BOOST_CHECK_EQUAL( r, rational_type(9, 4) );
755}
756
757// Division tests
758BOOST_AUTO_TEST_CASE_TEMPLATE( rational_division_test, T,
759 all_signed_test_types )
760{
761 typedef boost::rational<T> rational_type;
762
763 BOOST_CHECK_EQUAL( rational_type(-1, 20) / rational_type(4, 5),
764 rational_type(-1, 16) );
765 BOOST_CHECK_EQUAL( rational_type( 5, 6) / static_cast<T>(7),
766 rational_type( 5, 42) );
767 BOOST_CHECK_EQUAL( static_cast<T>(8) / rational_type(2, 7),
768 static_cast<T>(28) );
769
770 BOOST_CHECK_THROW( rational_type(23, 17) / rational_type(),
771 boost::bad_rational );
772 BOOST_CHECK_THROW( rational_type( 4, 15) / static_cast<T>(0),
773 boost::bad_rational );
774
775 rational_type r = rational_type( 4, 3 );
776
777 r /= rational_type( 5, 4 );
778 BOOST_CHECK_EQUAL( r, rational_type(16, 15) );
779
780 r /= static_cast<T>( 4 );
781 BOOST_CHECK_EQUAL( r, rational_type( 4, 15) );
782
783 BOOST_CHECK_THROW( r /= rational_type(), boost::bad_rational );
784 BOOST_CHECK_THROW( r /= static_cast<T>(0), boost::bad_rational );
785
786 BOOST_CHECK_EQUAL( rational_type(-1) / rational_type(-3),
787 rational_type(1, 3) );
788}
789
790// Tests for operations on self
791BOOST_AUTO_TEST_CASE_TEMPLATE( rational_self_operations_test, T,
792 all_signed_test_types )
793{
794 typedef boost::rational<T> rational_type;
795
796 rational_type r = rational_type( 4, 3 );
797
798 r += r;
799 BOOST_CHECK_EQUAL( r, rational_type( 8, 3) );
800
801 r *= r;
802 BOOST_CHECK_EQUAL( r, rational_type(64, 9) );
803
804 r /= r;
805 BOOST_CHECK_EQUAL( r, rational_type( 1, 1) );
806
807 r -= r;
808 BOOST_CHECK_EQUAL( r, rational_type( 0, 1) );
809
810 BOOST_CHECK_THROW( r /= r, boost::bad_rational );
811}
812
813BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_and_lcm_on_rationals, T, all_signed_test_types )
814{
815 typedef boost::rational<T> rational;
816 BOOST_CHECK_EQUAL(boost::integer::gcd(rational(1, 4), rational(1, 3)),
817 rational(1, 12));
818 BOOST_CHECK_EQUAL(boost::integer::lcm(rational(1, 4), rational(1, 3)),
819 rational(1));
820}
821
822// Assignment tests
823BOOST_AUTO_TEST_CASE_TEMPLATE(rational_mixed_test, T,
824 /*all_signed_test_types*/ builtin_signed_test_types)
825{
826 {
827 typedef boost::rational<boost::intmax_t> rational_type;
828 T val1 = 20;
829 boost::intmax_t val2 = 30;
830
831 rational_type r(val1, val2);
832 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
833
834 r.assign(val1, val2);
835 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
836 }
837 {
838 typedef boost::rational<boost::uintmax_t> rational_type2;
839
840 T val1 = 20;
841 boost::uintmax_t val3 = 30;
842
843 rational_type2 r2(val1, val3);
844 BOOST_CHECK_EQUAL(r2, rational_type2(20, 30));
845
846 r2.assign(val1, val3);
847 BOOST_CHECK_EQUAL(r2, rational_type2(20, 30));
848 }
849 {
850 typedef boost::rational<short> rational_type;
851 T val1 = 20;
852 short val2 = 30;
853
854 rational_type r(val1, val2);
855 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
856
857 r.assign(val1, val2);
858 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
859 }
860 {
861 typedef boost::rational<unsigned short> rational_type;
862 T val1 = 20;
863 unsigned short val2 = 30;
864
865 rational_type r(val1, val2);
866 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
867
868 r.assign(val1, val2);
869 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
870 }
871 {
872 typedef boost::rational<long> rational_type;
873 T val1 = 20;
874 long val2 = 30;
875
876 rational_type r(val1, val2);
877 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
878
879 r.assign(val1, val2);
880 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
881 }
882 {
883 typedef boost::rational<unsigned long> rational_type;
884 T val1 = 20;
885 unsigned long val2 = 30;
886
887 rational_type r(val1, val2);
888 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
889
890 r.assign(val1, val2);
891 BOOST_CHECK_EQUAL(r, rational_type(20, 30));
892 }
893 {
894 typedef boost::rational<boost::intmax_t> rational_type;
895 T val1 = 20;
896 boost::intmax_t val2 = -30;
897
898 rational_type r(val1, val2);
899 BOOST_CHECK_EQUAL(r, rational_type(20, -30));
900
901 r.assign(val1, val2);
902 BOOST_CHECK_EQUAL(r, rational_type(20, -30));
903 }
904 {
905 typedef boost::rational<short> rational_type;
906 T val1 = -20;
907 short val2 = -30;
908
909 rational_type r(val1, val2);
910 BOOST_CHECK_EQUAL(r, rational_type(-20, -30));
911
912 r.assign(val1, val2);
913 BOOST_CHECK_EQUAL(r, rational_type(-20, -30));
914 }
915 {
916 typedef boost::rational<long> rational_type;
917 T val1 = -20;
918 long val2 = 30;
919
920 rational_type r(val1, val2);
921 BOOST_CHECK_EQUAL(r, rational_type(-20, 30));
922
923 r.assign(val1, val2);
924 BOOST_CHECK_EQUAL(r, rational_type(-20, 30));
925 }
926}
927
928BOOST_AUTO_TEST_CASE(conversions)
929{
930 typedef boost::rational<boost::int32_t> signed_rat;
931
932 boost::int32_t signed_max = (std::numeric_limits<boost::int32_t>::max)();
933 boost::int32_t signed_min = (std::numeric_limits<boost::int32_t>::min)();
934 boost::int32_t signed_min_num = signed_min + 1;
935
936 BOOST_CHECK_EQUAL(signed_rat(signed_max).numerator(), signed_max);
937 BOOST_CHECK_EQUAL(signed_rat(signed_min).numerator(), signed_min);
938 BOOST_CHECK_EQUAL(signed_rat(signed_max, 1).numerator(), signed_max);
939 BOOST_CHECK_EQUAL(signed_rat(signed_min, 1).numerator(), signed_min);
940 BOOST_CHECK_EQUAL(signed_rat(1, signed_max).denominator(), signed_max);
941 BOOST_CHECK_EQUAL(signed_rat(1, signed_min_num).denominator(), -signed_min_num);
942 // This throws because we can't negate signed_min:
943 BOOST_CHECK_THROW(signed_rat(1, signed_min).denominator(), std::domain_error);
944
945 signed_rat sr;
946 BOOST_CHECK_EQUAL(sr.assign(signed_max, 1).numerator(), signed_max);
947 BOOST_CHECK_EQUAL(sr.assign(1, signed_max).denominator(), signed_max);
948 BOOST_CHECK_EQUAL(sr.assign(signed_min, 1).numerator(), signed_min);
949 BOOST_CHECK_EQUAL(sr.assign(1, signed_min_num).denominator(), -signed_min_num);
950 BOOST_CHECK_THROW(sr.assign(1, signed_min), std::domain_error);
951
952 BOOST_CHECK_EQUAL((sr = signed_max).numerator(), signed_max);
953 BOOST_CHECK_EQUAL((sr = signed_min).numerator(), signed_min);
954
955 boost::int64_t big_signed_max = (std::numeric_limits<boost::int32_t>::max)();
956 boost::int64_t big_signed_min = (std::numeric_limits<boost::int32_t>::min)();
957 boost::int64_t big_signed_min_num = signed_min + 1;
958
959 BOOST_CHECK_EQUAL(signed_rat(big_signed_max).numerator(), big_signed_max);
960 BOOST_CHECK_EQUAL(signed_rat(big_signed_min).numerator(), big_signed_min);
961 BOOST_CHECK_EQUAL(signed_rat(big_signed_max, 1).numerator(), big_signed_max);
962 BOOST_CHECK_EQUAL(signed_rat(big_signed_min, 1).numerator(), big_signed_min);
963 BOOST_CHECK_EQUAL(signed_rat(1, big_signed_max).denominator(), big_signed_max);
964 BOOST_CHECK_EQUAL(signed_rat(1, big_signed_min_num).denominator(), -big_signed_min_num);
965 // This throws because we can't negate big_signed_min:
966 BOOST_CHECK_THROW(signed_rat(1, big_signed_min).denominator(), std::domain_error);
967
968 BOOST_CHECK_EQUAL(sr.assign(big_signed_max, 1).numerator(), big_signed_max);
969 BOOST_CHECK_EQUAL(sr.assign(1, big_signed_max).denominator(), big_signed_max);
970 BOOST_CHECK_EQUAL(sr.assign(big_signed_min, 1).numerator(), big_signed_min);
971 BOOST_CHECK_EQUAL(sr.assign(1, big_signed_min_num).denominator(), -big_signed_min_num);
972 BOOST_CHECK_THROW(sr.assign(1, big_signed_min), std::domain_error);
973
974 BOOST_CHECK_EQUAL((sr = big_signed_max).numerator(), big_signed_max);
975 BOOST_CHECK_EQUAL((sr = big_signed_min).numerator(), big_signed_min);
976
977 ++big_signed_max;
978 --big_signed_min;
979 BOOST_CHECK_THROW(signed_rat(big_signed_max).numerator(), std::domain_error);
980 BOOST_CHECK_THROW(signed_rat(big_signed_min).numerator(), std::domain_error);
981 BOOST_CHECK_THROW(signed_rat(big_signed_max, 1).numerator(), std::domain_error);
982 BOOST_CHECK_THROW(signed_rat(big_signed_min, 1).numerator(), std::domain_error);
983 BOOST_CHECK_THROW(signed_rat(1, big_signed_max).denominator(), std::domain_error);
984
985 BOOST_CHECK_THROW(sr.assign(big_signed_max, 1).numerator(), std::domain_error);
986 BOOST_CHECK_THROW(sr.assign(1, big_signed_max).denominator(), std::domain_error);
987 BOOST_CHECK_THROW(sr.assign(big_signed_min, 1).numerator(), std::domain_error);
988
989 BOOST_CHECK_THROW((sr = big_signed_max).numerator(), std::domain_error);
990 BOOST_CHECK_THROW((sr = big_signed_min).numerator(), std::domain_error);
991
992 boost::int16_t small_signed_max = (std::numeric_limits<boost::int16_t>::max)();
993 boost::int16_t small_signed_min = (std::numeric_limits<boost::int16_t>::min)();
994
995 BOOST_CHECK_EQUAL(signed_rat(small_signed_max).numerator(), small_signed_max);
996 BOOST_CHECK_EQUAL(signed_rat(small_signed_min).numerator(), small_signed_min);
997 BOOST_CHECK_EQUAL(signed_rat(small_signed_max, 1).numerator(), small_signed_max);
998 BOOST_CHECK_EQUAL(signed_rat(small_signed_min, 1).numerator(), small_signed_min);
999 BOOST_CHECK_EQUAL(signed_rat(1, small_signed_max).denominator(), small_signed_max);
1000 BOOST_CHECK_EQUAL(signed_rat(1, small_signed_min).denominator(), -static_cast<boost::int32_t>(small_signed_min));
1001
1002 BOOST_CHECK_EQUAL(sr.assign(small_signed_max, 1).numerator(), small_signed_max);
1003 BOOST_CHECK_EQUAL(sr.assign(1, small_signed_max).denominator(), small_signed_max);
1004 BOOST_CHECK_EQUAL(sr.assign(small_signed_min, 1).numerator(), small_signed_min);
1005 BOOST_CHECK_EQUAL(sr.assign(1, small_signed_min).denominator(), -static_cast<boost::int32_t>(small_signed_min));
1006
1007 BOOST_CHECK_EQUAL((sr = small_signed_max).numerator(), small_signed_max);
1008 BOOST_CHECK_EQUAL((sr = small_signed_min).numerator(), small_signed_min);
1009
1010 boost::uint32_t unsigned_max = signed_max;
1011 BOOST_CHECK_EQUAL(signed_rat(unsigned_max).numerator(), signed_max);
1012 BOOST_CHECK_EQUAL(signed_rat(unsigned_max, 1).numerator(), signed_max);
1013 BOOST_CHECK_EQUAL(signed_rat(1, unsigned_max).denominator(), signed_max);
1014
1015 BOOST_CHECK_EQUAL(sr.assign(unsigned_max, 1).numerator(), signed_max);
1016 BOOST_CHECK_EQUAL(sr.assign(1, unsigned_max).denominator(), signed_max);
1017 BOOST_CHECK_EQUAL((sr = unsigned_max).numerator(), signed_max);
1018 ++unsigned_max;
1019 BOOST_CHECK_THROW(signed_rat(unsigned_max).numerator(), std::domain_error);
1020 BOOST_CHECK_THROW(signed_rat(unsigned_max, 1).numerator(), std::domain_error);
1021 BOOST_CHECK_THROW(signed_rat(1, unsigned_max).denominator(), std::domain_error);
1022
1023 BOOST_CHECK_THROW(sr.assign(unsigned_max, 1).numerator(), std::domain_error);
1024 BOOST_CHECK_THROW(sr.assign(1, unsigned_max).denominator(), std::domain_error);
1025 BOOST_CHECK_THROW((sr = unsigned_max).numerator(), std::domain_error);
1026
1027 boost::uint64_t big_unsigned_max = signed_max;
1028 BOOST_CHECK_EQUAL(signed_rat(big_unsigned_max).numerator(), signed_max);
1029 BOOST_CHECK_EQUAL(signed_rat(big_unsigned_max, 1).numerator(), signed_max);
1030 BOOST_CHECK_EQUAL(signed_rat(1, big_unsigned_max).denominator(), signed_max);
1031
1032 BOOST_CHECK_EQUAL(sr.assign(big_unsigned_max, 1).numerator(), signed_max);
1033 BOOST_CHECK_EQUAL(sr.assign(1, big_unsigned_max).denominator(), signed_max);
1034 BOOST_CHECK_EQUAL((sr = big_unsigned_max).numerator(), signed_max);
1035 ++big_unsigned_max;
1036 BOOST_CHECK_THROW(signed_rat(big_unsigned_max).numerator(), std::domain_error);
1037 BOOST_CHECK_THROW(signed_rat(big_unsigned_max, 1).numerator(), std::domain_error);
1038 BOOST_CHECK_THROW(signed_rat(1, big_unsigned_max).denominator(), std::domain_error);
1039
1040 BOOST_CHECK_THROW(sr.assign(big_unsigned_max, 1).numerator(), std::domain_error);
1041 BOOST_CHECK_THROW(sr.assign(1, big_unsigned_max).denominator(), std::domain_error);
1042 BOOST_CHECK_THROW((sr = big_unsigned_max).numerator(), std::domain_error);
1043
1044 boost::uint16_t small_unsigned_max = signed_max;
1045 BOOST_CHECK_EQUAL(signed_rat(small_unsigned_max).numerator(), small_unsigned_max);
1046 BOOST_CHECK_EQUAL(signed_rat(small_unsigned_max, 1).numerator(), small_unsigned_max);
1047 BOOST_CHECK_EQUAL(signed_rat(1, small_unsigned_max).denominator(), small_unsigned_max);
1048
1049 BOOST_CHECK_EQUAL(sr.assign(small_unsigned_max, 1).numerator(), small_unsigned_max);
1050 BOOST_CHECK_EQUAL(sr.assign(1, small_unsigned_max).denominator(), small_unsigned_max);
1051 BOOST_CHECK_EQUAL((sr = small_unsigned_max).numerator(), small_unsigned_max);
1052
1053 // Over again with unsigned rational type:
1054 typedef boost::rational<boost::uint32_t> unsigned_rat;
1055
1056 unsigned_max = (std::numeric_limits<boost::uint32_t>::max)();
1057
1058 BOOST_CHECK_EQUAL(unsigned_rat(unsigned_max).numerator(), unsigned_max);
1059 BOOST_CHECK_EQUAL(unsigned_rat(unsigned_max, 1).numerator(), unsigned_max);
1060 BOOST_CHECK_EQUAL(unsigned_rat(1, unsigned_max).denominator(), unsigned_max);
1061
1062 unsigned_rat ur;
1063 BOOST_CHECK_EQUAL((ur = unsigned_max).numerator(), unsigned_max);
1064 BOOST_CHECK_EQUAL(ur.assign(unsigned_max, 1).numerator(), unsigned_max);
1065 BOOST_CHECK_EQUAL(ur.assign(1, unsigned_max).denominator(), unsigned_max);
1066
1067 big_unsigned_max = unsigned_max;
1068 BOOST_CHECK_EQUAL(unsigned_rat(big_unsigned_max).numerator(), big_unsigned_max);
1069 BOOST_CHECK_EQUAL(unsigned_rat(big_unsigned_max, 1).numerator(), big_unsigned_max);
1070 BOOST_CHECK_EQUAL(unsigned_rat(1, big_unsigned_max).denominator(), big_unsigned_max);
1071 BOOST_CHECK_EQUAL((ur = big_unsigned_max).numerator(), big_unsigned_max);
1072 BOOST_CHECK_EQUAL(ur.assign(big_unsigned_max, 1).numerator(), big_unsigned_max);
1073 BOOST_CHECK_EQUAL(ur.assign(1, big_unsigned_max).denominator(), big_unsigned_max);
1074 ++big_unsigned_max;
1075 BOOST_CHECK_THROW(unsigned_rat(big_unsigned_max).numerator(), std::domain_error);
1076 BOOST_CHECK_THROW(unsigned_rat(big_unsigned_max, 1).numerator(), std::domain_error);
1077 BOOST_CHECK_THROW(unsigned_rat(1, big_unsigned_max).denominator(), std::domain_error);
1078 BOOST_CHECK_THROW((ur = big_unsigned_max).numerator(), std::domain_error);
1079 BOOST_CHECK_THROW(ur.assign(big_unsigned_max, 1).numerator(), std::domain_error);
1080 BOOST_CHECK_THROW(ur.assign(1, big_unsigned_max).denominator(), std::domain_error);
1081
1082 BOOST_CHECK_EQUAL(unsigned_rat(small_unsigned_max).numerator(), small_unsigned_max);
1083 BOOST_CHECK_EQUAL(unsigned_rat(small_unsigned_max, 1).numerator(), small_unsigned_max);
1084 BOOST_CHECK_EQUAL(unsigned_rat(1, small_unsigned_max).denominator(), small_unsigned_max);
1085 BOOST_CHECK_EQUAL((ur = small_unsigned_max).numerator(), small_unsigned_max);
1086 BOOST_CHECK_EQUAL(ur.assign(small_unsigned_max, 1).numerator(), small_unsigned_max);
1087 BOOST_CHECK_EQUAL(ur.assign(1, small_unsigned_max).denominator(), small_unsigned_max);
1088
1089 BOOST_CHECK_EQUAL(unsigned_rat(signed_max).numerator(), signed_max);
1090 BOOST_CHECK_EQUAL(unsigned_rat(signed_max, 1).numerator(), signed_max);
1091 BOOST_CHECK_EQUAL(unsigned_rat(1, signed_max).denominator(), signed_max);
1092 BOOST_CHECK_EQUAL((ur = signed_max).numerator(), signed_max);
1093 BOOST_CHECK_EQUAL(ur.assign(signed_max, 1).numerator(), signed_max);
1094 BOOST_CHECK_EQUAL(ur.assign(1, signed_max).denominator(), signed_max);
1095 BOOST_CHECK_THROW(unsigned_rat(signed_min).numerator(), std::domain_error);
1096 BOOST_CHECK_THROW(unsigned_rat(signed_min, 1).numerator(), std::domain_error);
1097 BOOST_CHECK_THROW(unsigned_rat(1, signed_min).denominator(), std::domain_error);
1098 BOOST_CHECK_THROW((ur = signed_min).numerator(), std::domain_error);
1099 BOOST_CHECK_THROW(ur.assign(signed_min, 1).numerator(), std::domain_error);
1100 BOOST_CHECK_THROW(ur.assign(1, signed_min).denominator(), std::domain_error);
1101
1102 big_signed_max = unsigned_max;
1103 BOOST_CHECK_EQUAL(unsigned_rat(big_signed_max).numerator(), unsigned_max);
1104 BOOST_CHECK_EQUAL(unsigned_rat(big_signed_max, 1).numerator(), unsigned_max);
1105 BOOST_CHECK_EQUAL(unsigned_rat(1, big_signed_max).denominator(), unsigned_max);
1106 BOOST_CHECK_EQUAL((ur = big_signed_max).numerator(), unsigned_max);
1107 BOOST_CHECK_EQUAL(ur.assign(big_signed_max, 1).numerator(), unsigned_max);
1108 BOOST_CHECK_EQUAL(ur.assign(1, big_signed_max).denominator(), unsigned_max);
1109 ++big_signed_max;
1110 BOOST_CHECK_THROW(unsigned_rat(big_signed_max).numerator(), std::domain_error);
1111 BOOST_CHECK_THROW(unsigned_rat(big_signed_max, 1).numerator(), std::domain_error);
1112 BOOST_CHECK_THROW(unsigned_rat(1, big_signed_max).denominator(), std::domain_error);
1113 BOOST_CHECK_THROW((ur = big_signed_max).numerator(), std::domain_error);
1114 BOOST_CHECK_THROW(ur.assign(big_signed_max, 1).numerator(), std::domain_error);
1115 BOOST_CHECK_THROW(ur.assign(1, big_signed_max).denominator(), std::domain_error);
1116 big_signed_max = -1;
1117 BOOST_CHECK_THROW(unsigned_rat(big_signed_max).numerator(), std::domain_error);
1118 BOOST_CHECK_THROW(unsigned_rat(big_signed_max, 1).numerator(), std::domain_error);
1119 BOOST_CHECK_THROW(unsigned_rat(1, big_signed_max).denominator(), std::domain_error);
1120 BOOST_CHECK_THROW((ur = big_signed_max).numerator(), std::domain_error);
1121 BOOST_CHECK_THROW(ur.assign(big_signed_max, 1).numerator(), std::domain_error);
1122 BOOST_CHECK_THROW(ur.assign(1, big_signed_max).denominator(), std::domain_error);
1123
1124 BOOST_CHECK_EQUAL(unsigned_rat(small_signed_max).numerator(), small_signed_max);
1125 BOOST_CHECK_EQUAL(unsigned_rat(small_signed_max, 1).numerator(), small_signed_max);
1126 BOOST_CHECK_EQUAL(unsigned_rat(1, small_signed_max).denominator(), small_signed_max);
1127 BOOST_CHECK_EQUAL((ur = small_signed_max).numerator(), small_signed_max);
1128 BOOST_CHECK_EQUAL(ur.assign(small_signed_max, 1).numerator(), small_signed_max);
1129 BOOST_CHECK_EQUAL(ur.assign(1, small_signed_max).denominator(), small_signed_max);
1130 small_signed_max = -1;
1131 BOOST_CHECK_THROW(unsigned_rat(small_signed_max).numerator(), std::domain_error);
1132 BOOST_CHECK_THROW(unsigned_rat(small_signed_max, 1).numerator(), std::domain_error);
1133 BOOST_CHECK_THROW(unsigned_rat(1, small_signed_max).denominator(), std::domain_error);
1134 BOOST_CHECK_THROW((ur = small_signed_max).numerator(), std::domain_error);
1135 BOOST_CHECK_THROW(ur.assign(small_signed_max, 1).numerator(), std::domain_error);
1136 BOOST_CHECK_THROW(ur.assign(1, small_signed_max).denominator(), std::domain_error);
1137}
1138
1139BOOST_AUTO_TEST_SUITE_END()
1140
1141
1142// The non-basic rational operations suite
1143BOOST_AUTO_TEST_SUITE( rational_extras_suite )
1144
1145#ifndef BOOST_NO_IOSTREAM
1146// Output test
1147BOOST_AUTO_TEST_CASE_TEMPLATE( rational_output_test, T, all_signed_test_types )
1148{
1149 using namespace std;
1150 typedef boost::rational<T> rational_type;
1151
1152 // Basic test
1153 ostringstream oss;
1154
1155 oss << rational_type( 44, 14 );
1156 BOOST_CHECK_EQUAL( oss.str(), "22/7" );
1157
1158 // Width
1159 oss.clear(); oss.str( s: "" );
1160 oss << setw( 5 ) << setfill('*') << rational_type( 1, 2 ) << 'r';
1161 BOOST_CHECK_EQUAL( oss.str(), "**1/2r" ); // not "****1/2r"
1162
1163 // Positive-sign
1164 oss.clear(); oss.str( s: "" );
1165 oss << showpos << rational_type( 2, 3 ) << noshowpos;
1166 BOOST_CHECK_EQUAL( oss.str(), "+2/3" ); // not "+2/+3"
1167
1168 // Internal padding
1169 oss.clear(); oss.str( s: "" );
1170 oss << setw( 8 ) << internal << rational_type( 36, -15 ) << right << 'r';
1171 BOOST_CHECK_EQUAL( oss.str(), "-***12/5r" ); // not "-*****12/5r"
1172
1173 // Showbase prefix
1174 oss.clear(); oss.str( s: "" );
1175 oss << showbase << hex << rational_type( 34, 987 ) << noshowbase << dec;
1176 BOOST_CHECK_EQUAL( oss.str(), "0x22/3db" ); // not "0x22/0x3db"
1177}
1178
1179// Input test, failing
1180BOOST_AUTO_TEST_CASE_TEMPLATE( rational_input_failing_test, T,
1181 all_signed_test_types )
1182{
1183 std::istringstream iss( "" );
1184 boost::rational<T> r;
1185
1186 iss >> r;
1187 BOOST_CHECK( !iss );
1188 BOOST_CHECK( !iss.bad() );
1189
1190 iss.clear();
1191 iss.str( s: "42" );
1192 iss >> r;
1193 BOOST_CHECK( !iss );
1194
1195 iss.clear();
1196 iss.str( s: "57A" );
1197 iss >> r;
1198 BOOST_CHECK( !iss );
1199
1200 iss.clear();
1201 iss.str( s: "20-20" );
1202 iss >> r;
1203 BOOST_CHECK( !iss );
1204
1205 iss.clear();
1206 iss.str( s: "1/" );
1207 iss >> r;
1208 BOOST_CHECK( !iss );
1209
1210 iss.clear();
1211 iss.str( s: "1/ 2" );
1212 iss >> r;
1213 BOOST_CHECK( !iss );
1214
1215 iss.clear();
1216 iss.str( s: "1 /2" );
1217 iss >> r;
1218 BOOST_CHECK( !iss );
1219
1220 // Illegal value check(s)
1221 typedef std::numeric_limits<T> limits_type;
1222
1223 iss.clear();
1224 iss.str( s: "3/0" );
1225 iss >> r;
1226 BOOST_CHECK( !iss );
1227
1228 if ( limits_type::is_signed && limits_type::is_bounded &&
1229 limits_type::min BOOST_PREVENT_MACRO_SUBSTITUTION () +
1230 limits_type::max BOOST_PREVENT_MACRO_SUBSTITUTION () < T(0) )
1231 {
1232 std::ostringstream oss;
1233
1234 oss << 1 << '/' << limits_type::min BOOST_PREVENT_MACRO_SUBSTITUTION ();
1235 iss.clear();
1236 iss.str( s: oss.str() );
1237 iss.exceptions( except: std::ios::failbit );
1238 BOOST_CHECK( iss.good() );
1239 BOOST_CHECK_THROW( iss >> r, boost::bad_rational );
1240 BOOST_CHECK( iss.fail() && !iss.bad() );
1241 iss.exceptions( except: std::ios::goodbit );
1242 }
1243}
1244
1245// Input test, passing
1246BOOST_AUTO_TEST_CASE_TEMPLATE( rational_input_passing_test, T,
1247 all_signed_test_types )
1248{
1249 typedef boost::rational<T> rational_type;
1250
1251 std::istringstream iss( "1/2 12" );
1252 rational_type r;
1253 int n = 0;
1254
1255 BOOST_CHECK( iss >> r >> n );
1256 BOOST_CHECK_EQUAL( r, rational_type(1, 2) );
1257 BOOST_CHECK_EQUAL( n, 12 );
1258
1259 iss.clear();
1260 iss.str( s: "34/67" );
1261 BOOST_CHECK( iss >> r );
1262 BOOST_CHECK_EQUAL( r, rational_type(34, 67) );
1263
1264 iss.clear();
1265 iss.str( s: "-3/-6" );
1266 BOOST_CHECK( iss >> r );
1267 BOOST_CHECK_EQUAL( r, rational_type(1, 2) );
1268}
1269#endif // BOOST_NO_IOSTREAM
1270
1271// Conversion test
1272BOOST_AUTO_TEST_CASE( rational_cast_test )
1273{
1274 // Note that these are not generic. The problem is that rational_cast<T>
1275 // requires a conversion from IntType to T. However, for a user-defined
1276 // IntType, it is not possible to define such a conversion except as an
1277 // "operator T()". This causes problems with overloading resolution.
1278 boost::rational<int> const half( 1, 2 );
1279
1280 BOOST_CHECK_CLOSE( boost::rational_cast<double>(half), 0.5, 0.01 );
1281 BOOST_CHECK_EQUAL( boost::rational_cast<int>(half), 0 );
1282 BOOST_CHECK_EQUAL( boost::rational_cast<MyInt>(half), MyInt() );
1283 BOOST_CHECK_EQUAL( boost::rational_cast<boost::rational<MyInt> >(half),
1284 boost::rational<MyInt>(1, 2) );
1285
1286 // Conversions via explicit-marked constructors
1287 // (Note that the "explicit" mark prevents conversion to
1288 // boost::rational<MyOverflowingUnsigned>.)
1289 boost::rational<MyInt> const threehalves( 3, 2 );
1290
1291 BOOST_CHECK_EQUAL( boost::rational_cast<MyOverflowingUnsigned>(threehalves),
1292 MyOverflowingUnsigned(1u) );
1293 //
1294 // Converting constructor should throw if a bad rational number results:
1295 //
1296 BOOST_CHECK_THROW(boost::rational<short>(boost::rational<long>(1, 1 << sizeof(short) * CHAR_BIT)), boost::bad_rational);
1297 //
1298 // New tests from checked narrowing conversions:
1299 //
1300 BOOST_CHECK_THROW(boost::rational<unsigned>(-1), boost::bad_rational);
1301 BOOST_CHECK_THROW(boost::rational<unsigned>(-1, 1), boost::bad_rational);
1302 BOOST_CHECK_THROW(boost::rational<unsigned>(1, -1), boost::bad_rational);
1303 unsigned ui_max = (std::numeric_limits<unsigned>::max)();
1304 BOOST_CHECK_THROW(boost::rational<int>(static_cast<unsigned>(ui_max)), boost::bad_rational);
1305 BOOST_CHECK_THROW(boost::rational<int>(ui_max, 1u), boost::bad_rational);
1306 BOOST_CHECK_THROW(boost::rational<int>(1u, ui_max), boost::bad_rational);
1307 //
1308 // Check assignments that should succeed from both wider and narrower types:
1309 //
1310 boost::rational<boost::int32_t> rat;
1311#ifndef BOOST_NO_INT64_T
1312 boost::int64_t ll, ll1(1);
1313 boost::uint64_t ull, ull1(1);
1314 boost::int32_t imax = (std::numeric_limits<boost::int32_t>::max)();
1315 boost::int32_t imin = (std::numeric_limits<boost::int32_t>::min)();
1316 ll = imax;
1317 rat.assign(n: ll, d: ll1);
1318 BOOST_CHECK_EQUAL(rat.numerator(), imax);
1319 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1320 ++ll;
1321 BOOST_CHECK_THROW(rat.assign(ll, ll1), boost::bad_rational);
1322 ll = imin;
1323 rat.assign(n: ll, d: ll1);
1324 BOOST_CHECK_EQUAL(rat.numerator(), imin);
1325 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1326 --ll;
1327 BOOST_CHECK_THROW(rat.assign(ll, ll1), boost::bad_rational);
1328 ull = imax;
1329 rat.assign(n: ull, d: ull1);
1330 BOOST_CHECK_EQUAL(rat.numerator(), imax);
1331 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1332 ++ull;
1333 BOOST_CHECK_THROW(rat.assign(ull, ull1), boost::bad_rational);
1334 ull = 0;
1335 rat.assign(n: ull, d: ull1);
1336 BOOST_CHECK_EQUAL(rat.numerator(), 0);
1337 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1338#endif
1339 boost::int16_t smax = (std::numeric_limits<boost::int16_t>::max)();
1340 boost::int16_t smin = (std::numeric_limits<boost::int16_t>::min)();
1341 boost::int16_t s1 = 1;
1342 rat.assign(n: smax, d: s1);
1343 BOOST_CHECK_EQUAL(rat.numerator(), smax);
1344 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1345 rat.assign(n: smin, d: s1);
1346 BOOST_CHECK_EQUAL(rat.numerator(), smin);
1347 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1348 boost::uint16_t usmax = (std::numeric_limits<boost::uint16_t>::max)();
1349 boost::uint16_t usmin = (std::numeric_limits<boost::uint16_t>::min)();
1350 boost::uint16_t us1 = 1;
1351 rat.assign(n: usmax, d: us1);
1352 BOOST_CHECK_EQUAL(rat.numerator(), usmax);
1353 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1354 rat.assign(n: usmin, d: us1);
1355 BOOST_CHECK_EQUAL(rat.numerator(), usmin);
1356 BOOST_CHECK_EQUAL(rat.denominator(), 1);
1357 //
1358 // Over again with unsigned rational:
1359 //
1360 boost::rational<boost::uint32_t> urat;
1361 unsigned uimax = (std::numeric_limits<boost::uint32_t>::max)();
1362 unsigned uimin = (std::numeric_limits<boost::uint32_t>::min)();
1363#ifndef BOOST_NO_INT64_T
1364 ll = uimax;
1365 urat.assign(n: ll, d: ll1);
1366 BOOST_CHECK_EQUAL(urat.numerator(), uimax);
1367 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1368 ++ll;
1369 BOOST_CHECK_THROW(urat.assign(ll, ll1), boost::bad_rational);
1370 ll = uimin;
1371 urat.assign(n: ll, d: ll1);
1372 BOOST_CHECK_EQUAL(urat.numerator(), uimin);
1373 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1374 --ll;
1375 BOOST_CHECK_THROW(urat.assign(ll, ll1), boost::bad_rational);
1376 ull = uimax;
1377 urat.assign(n: ull, d: ull1);
1378 BOOST_CHECK_EQUAL(urat.numerator(), uimax);
1379 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1380 ++ull;
1381 BOOST_CHECK_THROW(urat.assign(ull, ull1), boost::bad_rational);
1382 ull = 0;
1383 urat.assign(n: ull, d: ull1);
1384 BOOST_CHECK_EQUAL(urat.numerator(), 0);
1385 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1386#endif
1387 smin = 0;
1388 s1 = 1;
1389 urat.assign(n: smax, d: s1);
1390 BOOST_CHECK_EQUAL(urat.numerator(), smax);
1391 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1392 urat.assign(n: smin, d: s1);
1393 BOOST_CHECK_EQUAL(urat.numerator(), smin);
1394 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1395 urat.assign(n: usmax, d: us1);
1396 BOOST_CHECK_EQUAL(urat.numerator(), usmax);
1397 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1398 urat.assign(n: usmin, d: us1);
1399 BOOST_CHECK_EQUAL(urat.numerator(), usmin);
1400 BOOST_CHECK_EQUAL(urat.denominator(), 1);
1401 //
1402 // Conversions that must not be allowed:
1403 //
1404 BOOST_STATIC_ASSERT(!boost::is_convertible<float, boost::rational<int> >::value);
1405 BOOST_STATIC_ASSERT(!boost::is_convertible<double, boost::rational<int> >::value);
1406 BOOST_STATIC_ASSERT(!boost::is_convertible<long double, boost::rational<int> >::value);
1407 // And ones that should:
1408 BOOST_STATIC_ASSERT(boost::is_convertible<char, boost::rational<int> >::value);
1409 BOOST_STATIC_ASSERT(boost::is_convertible<signed char, boost::rational<int> >::value);
1410 BOOST_STATIC_ASSERT(boost::is_convertible<unsigned char, boost::rational<int> >::value);
1411 BOOST_STATIC_ASSERT(boost::is_convertible<short, boost::rational<int> >::value);
1412 BOOST_STATIC_ASSERT(boost::is_convertible<unsigned short, boost::rational<int> >::value);
1413 BOOST_STATIC_ASSERT(boost::is_convertible<int, boost::rational<int> >::value);
1414 BOOST_STATIC_ASSERT(boost::is_convertible<unsigned int, boost::rational<int> >::value);
1415 BOOST_STATIC_ASSERT(boost::is_convertible<long, boost::rational<int> >::value);
1416 BOOST_STATIC_ASSERT(boost::is_convertible<unsigned long, boost::rational<int> >::value);
1417}
1418
1419#ifndef BOOST_NO_MEMBER_TEMPLATES
1420// Cross-conversion constructor test
1421BOOST_AUTO_TEST_CASE( rational_cross_constructor_test )
1422{
1423 // This template will be repeated a lot.
1424 using boost::rational;
1425
1426 // Create a bunch of explicit conversions.
1427 rational<int> const half_i( 2, 4 );
1428 rational<unsigned> const half_u( half_i );
1429 rational<MyInt> const half_mi( half_i );
1430 rational<MyOverflowingUnsigned> const half_mu1(half_u), half_mu2(half_mi);
1431
1432 BOOST_CHECK_EQUAL( half_u.numerator(), 1u );
1433 BOOST_CHECK_EQUAL( half_u.denominator(), 2u );
1434 BOOST_CHECK_EQUAL( half_mi.numerator(), MyInt(1) );
1435 BOOST_CHECK_EQUAL( half_mi.denominator(), MyInt(2) );
1436 BOOST_CHECK_EQUAL( half_mu1.numerator(), MyOverflowingUnsigned(1u) );
1437 BOOST_CHECK_EQUAL( half_mu1.denominator(), MyOverflowingUnsigned(2u) );
1438 BOOST_CHECK_EQUAL( half_mu2.numerator(), MyOverflowingUnsigned(1u) );
1439 BOOST_CHECK_EQUAL( half_mu2.denominator(), MyOverflowingUnsigned(2u) );
1440
1441#if 0
1442 // This will fail since it needs an implicit conversion.
1443 // (Try it if your compiler supports C++11 lambdas.)
1444 BOOST_CHECK( [](rational<unsigned> x){return !!x;}(half_i) );
1445#endif
1446
1447 // Translation from a built-in unsigned type to a signed one is
1448 // implementation-defined, so hopefully we won't get a trap value.
1449 // (We're counting on static_cast<int>(UINT_MAX) being negative.)
1450 rational<unsigned> const too_small( 1u, UINT_MAX );
1451 rational<int> receiver;
1452
1453 BOOST_CHECK_THROW( receiver=rational<int>(too_small), boost::bad_rational );
1454}
1455#endif // BOOST_NO_MEMBER_TEMPLATES
1456
1457// Dice tests (a non-main test)
1458BOOST_AUTO_TEST_CASE_TEMPLATE( dice_roll_test, T, all_signed_test_types )
1459{
1460 typedef boost::rational<T> rational_type;
1461
1462 // Determine the mean number of times a fair six-sided die
1463 // must be thrown until each side has appeared at least once.
1464 rational_type r = T( 0 );
1465
1466 for ( int i = 1 ; i <= 6 ; ++i )
1467 {
1468 r += rational_type( 1, i );
1469 }
1470 r *= static_cast<T>( 6 );
1471
1472 BOOST_CHECK_EQUAL( r, rational_type(147, 10) );
1473}
1474
1475BOOST_AUTO_TEST_SUITE_END()
1476
1477
1478// The bugs, patches, and requests checking suite
1479BOOST_AUTO_TEST_SUITE( bug_patch_request_suite )
1480
1481// "rational operator< can overflow"
1482BOOST_AUTO_TEST_CASE( bug_798357_test )
1483{
1484 // Choose values such that rational-number comparisons will overflow if
1485 // the multiplication method (n1/d1 ? n2/d2 == n1*d2 ? n2*d1) is used.
1486 // (And make sure that the large components are relatively prime, so they
1487 // won't partially cancel to make smaller, more reasonable, values.)
1488 unsigned const n1 = UINT_MAX - 2u, d1 = UINT_MAX - 1u;
1489 unsigned const n2 = d1, d2 = UINT_MAX;
1490 boost::rational<MyOverflowingUnsigned> const r1( n1, d1 ), r2( n2, d2 );
1491
1492 BOOST_REQUIRE_EQUAL( boost::integer::gcd(n1, d1), 1u );
1493 BOOST_REQUIRE_EQUAL( boost::integer::gcd(n2, d2), 1u );
1494 BOOST_REQUIRE( n1 > UINT_MAX / d2 );
1495 BOOST_REQUIRE( n2 > UINT_MAX / d1 );
1496 BOOST_CHECK( r1 < r2 );
1497 BOOST_CHECK( !(r1 < r1) );
1498 BOOST_CHECK( !(r2 < r1) );
1499}
1500
1501// "rational::operator< fails for unsigned value types"
1502BOOST_AUTO_TEST_CASE( patch_1434821_test )
1503{
1504 // If a zero-rational v. positive-integer comparison involves negation, then
1505 // it may fail with unsigned types, which wrap around (for built-ins) or
1506 // throw/be-undefined (for user-defined types).
1507 boost::rational<unsigned> const r( 0u );
1508
1509 BOOST_CHECK( r < 1u );
1510}
1511
1512// "rational.hpp::gcd returns a negative value sometimes"
1513BOOST_AUTO_TEST_CASE( patch_1438626_test )
1514{
1515 // The issue only manifests with 2's-complement integers that use their
1516 // entire range of bits. [This means that ln(-INT_MIN)/ln(2) is an integer
1517 // and INT_MAX + INT_MIN == -1.] The common computer platforms match this.
1518#if (INT_MAX + INT_MIN == -1) && ((INT_MAX ^ INT_MIN) == -1)
1519 // If a GCD routine takes the absolute value of an argument only before
1520 // processing, it won't realize that -INT_MIN -> INT_MIN (i.e. no change
1521 // from negation) and will propagate a negative sign to its result.
1522 BOOST_REQUIRE_EQUAL( boost::integer::gcd(INT_MIN, 6), 2 );
1523
1524 // That is bad if the rational number type does not check for that
1525 // possibility during normalization.
1526 boost::rational<int> const r1( INT_MIN / 2 + 3, 6 ),
1527 r2( INT_MIN / 2 - 3, 6 ), r3 = r1 + r2;
1528
1529 // If the error happens, the signs of the components will be switched.
1530 // (The numerators' sum is INT_MIN, and its GCD with 6 would be negated.)
1531 BOOST_CHECK_EQUAL( r3.numerator(), INT_MIN / 2 );
1532 BOOST_CHECK_EQUAL( r3.denominator(), 3 );
1533#endif
1534}
1535
1536// The bug/patch numbers for the above 3 tests are from our SourceForge repo
1537// before we moved to our own SVN & Trac server. At the time this note is
1538// written, it seems that SourceForge has reset their tracking numbers at least
1539// once, so I don't know how to recover those old tickets. The ticket numbers
1540// for the following tests are from our SVN/Trac repo.
1541
1542//"narrowing conversion error with -std=c++0x in operator< with int_type != int"
1543BOOST_AUTO_TEST_CASE( ticket_5855_test )
1544{
1545 // The internals of operator< currently store a structure of two int_type
1546 // (where int_type is the component type of a boost::rational template
1547 // class) and two computed types. These computed types, results of
1548 // arithmetic operations among int_type values, are either int_type
1549 // themselves or a larger type that can implicitly convert to int_type.
1550 // Those conversions aren't usually a problem. But when an arithmetic
1551 // operation involving two values of a built-in scalar type smaller than int
1552 // are involved, the result is an int. But the resulting int-to-shorter
1553 // conversion is considered narrowing, resulting in a warning or error on
1554 // some compilers. Notably, C++11 compilers are supposed to consider it an
1555 // error.
1556 //
1557 // The solution is to force an explicit conversion, although it's otherwise
1558 // not needed. (The compiler can rescind the narrowing warning if the
1559 // results of the larger type still fit in the smaller one, and that proof
1560 // can be generated at constexpr time.)
1561 typedef short shorter_than_int_type;
1562 typedef boost::rational<shorter_than_int_type> rational_type;
1563
1564 bool const dummy = rational_type() < rational_type();
1565
1566 BOOST_REQUIRE( !dummy );
1567}
1568
1569// "rational::assign" doesn't even have the basic guarantee
1570BOOST_AUTO_TEST_CASE( ticket_9067_test )
1571{
1572 using boost::rational;
1573 using boost::integer::gcd;
1574
1575 rational<int> a( 6, -8 );
1576
1577 // Normalize to maintain invariants
1578 BOOST_CHECK_EQUAL( a.numerator(), -3 );
1579 BOOST_CHECK_EQUAL( a.denominator(), 4 );
1580 BOOST_CHECK( a.denominator() > 0 );
1581 BOOST_CHECK_EQUAL( gcd(a.numerator(), a.denominator()), 1 );
1582
1583 // Do we maintain the basic guarantee after a failed component-assign?
1584 BOOST_CHECK_THROW( a.assign(1, 0), boost::bad_rational );
1585 BOOST_CHECK_NE( a.denominator(), 0 );
1586 BOOST_CHECK( a.denominator() > 0 );
1587 BOOST_CHECK_EQUAL( gcd(a.numerator(), a.denominator()), 1 );
1588
1589 // Do we get the strong guarantee?
1590 BOOST_CHECK_EQUAL( a.numerator(), -3 );
1591 BOOST_CHECK_EQUAL( a.denominator(), 4 );
1592
1593#if INT_MIN + INT_MAX < 0
1594 // Try an example without a zero-denominator
1595 a = rational<int>( -9, 12 );
1596 BOOST_CHECK_EQUAL( a.numerator(), -3 );
1597 BOOST_CHECK_EQUAL( a.denominator(), 4 );
1598 BOOST_CHECK( a.denominator() > 0 );
1599 BOOST_CHECK_EQUAL( gcd(a.numerator(), a.denominator()), 1 );
1600 BOOST_CHECK_THROW( a.assign(-(INT_MIN + 1), INT_MIN), boost::bad_rational );
1601 BOOST_CHECK( a.denominator() > 0 );
1602 BOOST_CHECK_EQUAL( gcd(a.numerator(), a.denominator()), 1 );
1603 BOOST_CHECK_EQUAL( a.numerator(), -3 );
1604 BOOST_CHECK_EQUAL( a.denominator(), 4 );
1605#endif
1606}
1607
1608BOOST_AUTO_TEST_SUITE_END()
1609

source code of boost/libs/rational/test/rational_test.cpp