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 | |
73 | namespace { |
74 | |
75 | class 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<> |
79 | class MyInt : boost::operators<MyInt> |
80 | { |
81 | friend class MyOverflowingUnsigned; |
82 | int val; |
83 | public: |
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 | |
104 | inline MyInt operator+(const MyInt& rhs) { return rhs; } |
105 | inline MyInt operator-(const MyInt& rhs) { return MyInt(-rhs.val); } |
106 | inline std::istream& operator>>(std::istream& is, MyInt& i) { is >> i.val; return is; } |
107 | inline std::ostream& operator<<(std::ostream& os, const MyInt& i) { os << i.val; return os; } |
108 | inline 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. |
112 | class 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 | |
123 | public: |
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 | |
231 | inline MyOverflowingUnsigned abs( MyOverflowingUnsigned const &x ) { return x; } |
232 | |
233 | } // namespace |
234 | |
235 | |
236 | // Specialize numeric_limits for the custom types |
237 | namespace std |
238 | { |
239 | |
240 | template < > |
241 | class numeric_limits< MyInt > |
242 | { |
243 | typedef numeric_limits<int> limits_type; |
244 | |
245 | public: |
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 | |
291 | template < > |
292 | class numeric_limits< MyOverflowingUnsigned > |
293 | { |
294 | typedef numeric_limits<unsigned> limits_type; |
295 | |
296 | public: |
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 | |
351 | namespace { |
352 | |
353 | // This fixture replaces the check of rational's packing at the start of main. |
354 | class rational_size_check |
355 | { |
356 | typedef INT_TYPE int_type; |
357 | typedef ::boost::rational<int_type> rational_type; |
358 | |
359 | public: |
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. |
388 | class my_configuration |
389 | { |
390 | public: |
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.) |
433 | typedef ::boost::mpl::list<short, int, long> builtin_signed_test_types; |
434 | typedef ::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 |
451 | BOOST_GLOBAL_FIXTURE( rational_size_check ); |
452 | |
453 | |
454 | #if BOOST_CONTROL_RATIONAL_HAS_GCD |
455 | // The factoring function template suite |
456 | BOOST_AUTO_TEST_SUITE( factoring_suite ) |
457 | |
458 | // GCD tests |
459 | BOOST_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 |
477 | BOOST_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 | |
494 | BOOST_AUTO_TEST_SUITE_END() |
495 | #endif // BOOST_CONTROL_RATIONAL_HAS_GCD |
496 | |
497 | |
498 | // The basic test suite |
499 | BOOST_FIXTURE_TEST_SUITE( basic_rational_suite, my_configuration ) |
500 | |
501 | // Initialization tests |
502 | BOOST_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 |
536 | BOOST_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 |
555 | BOOST_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 |
613 | BOOST_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 |
629 | BOOST_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 |
652 | BOOST_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 | |
671 | BOOST_AUTO_TEST_SUITE_END() |
672 | |
673 | |
674 | // The rational arithmetic operations suite |
675 | BOOST_AUTO_TEST_SUITE( rational_arithmetic_suite ) |
676 | |
677 | // Addition & subtraction tests |
678 | BOOST_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 |
721 | BOOST_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 |
736 | BOOST_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 |
758 | BOOST_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 |
791 | BOOST_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 | |
813 | BOOST_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 |
823 | BOOST_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 | |
928 | BOOST_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 | |
1139 | BOOST_AUTO_TEST_SUITE_END() |
1140 | |
1141 | |
1142 | // The non-basic rational operations suite |
1143 | BOOST_AUTO_TEST_SUITE( rational_extras_suite ) |
1144 | |
1145 | #ifndef BOOST_NO_IOSTREAM |
1146 | // Output test |
1147 | BOOST_AUTO_TEST_CASE_TEMPLATE( , 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 |
1180 | BOOST_AUTO_TEST_CASE_TEMPLATE( , 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 |
1246 | BOOST_AUTO_TEST_CASE_TEMPLATE( , 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 |
1272 | BOOST_AUTO_TEST_CASE( ) |
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 |
1421 | BOOST_AUTO_TEST_CASE( ) |
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) |
1458 | BOOST_AUTO_TEST_CASE_TEMPLATE( , 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 | |
1475 | BOOST_AUTO_TEST_SUITE_END() |
1476 | |
1477 | |
1478 | // The bugs, patches, and requests checking suite |
1479 | BOOST_AUTO_TEST_SUITE( bug_patch_request_suite ) |
1480 | |
1481 | // "rational operator< can overflow" |
1482 | BOOST_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" |
1502 | BOOST_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" |
1513 | BOOST_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" |
1543 | BOOST_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 |
1570 | BOOST_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 | |
1608 | BOOST_AUTO_TEST_SUITE_END() |
1609 | |