1 //  Boost GCD & LCM common_factor.hpp test program  --------------------------//
2 
3 //  (C) Copyright Daryle Walker 2001, 2006.
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 
8 //  See http://www.boost.org for most recent version including documentation.
9 
10 //  Revision History
11 //  01 Dec 2006  Various fixes for old compilers (Joaquin M Lopez Munoz)
12 //  10 Nov 2006  Make long long and __int64 mutually exclusive (Daryle Walker)
13 //  04 Nov 2006  Use more built-in numeric types, binary-GCD (Daryle Walker)
14 //  03 Nov 2006  Use custom numeric types (Daryle Walker)
15 //  02 Nov 2006  Change to Boost.Test's unit test system (Daryle Walker)
16 //  07 Nov 2001  Initial version (Daryle Walker)
17 
18 #define BOOST_TEST_MAIN  "Boost.Math GCD & LCM unit tests"
19 
20 #include <boost/config.hpp>              // for BOOST_MSVC, etc.
21 #include <boost/detail/workaround.hpp>
22 #include <boost/math/common_factor.hpp>  // for boost::math::gcd, etc.
23 #include <boost/mpl/list.hpp>            // for boost::mpl::list
24 #include <boost/operators.hpp>
25 #include <boost/test/unit_test.hpp>
26 
27 #include <istream>  // for std::basic_istream
28 #include <limits>   // for std::numeric_limits
29 #include <ostream>  // for std::basic_ostream
30 
31 
32 namespace {
33 
34 // TODO: add polynominal/non-real type; especially after any switch to the
35 // binary-GCD algorithm for built-in types
36 
37 // Custom integer class (template)
38 template < typename IntType, int ID = 0 >
39 class my_wrapped_integer
40     : private ::boost::shiftable1<my_wrapped_integer<IntType, ID>,
41         ::boost::operators<my_wrapped_integer<IntType, ID> > >
42 {
43     // Helper type-aliases
44     typedef my_wrapped_integer    self_type;
45     typedef IntType self_type::*  bool_type;
46 
47     // Member data
48     IntType  v_;
49 
50 public:
51     // Template parameters
52     typedef IntType  int_type;
53 
54     BOOST_STATIC_CONSTANT(int,id = ID);
55 
56     // Lifetime management (use automatic destructor and copy constructor)
my_wrapped_integer(int_type const & v=int_type ())57     my_wrapped_integer( int_type const &v = int_type() )  : v_( v )  {}
58 
59     // Accessors
value() const60     int_type  value() const  { return this->v_; }
61 
62     // Operators (use automatic copy assignment)
operator bool_type() const63     operator bool_type() const  { return this->v_ ? &self_type::v_ : 0; }
64 
operator ++()65     self_type &  operator ++()  { ++this->v_; return *this; }
operator --()66     self_type &  operator --()  { --this->v_; return *this; }
67 
operator ~() const68     self_type  operator ~() const  { return self_type( ~this->v_ ); }
operator !() const69     self_type  operator !() const  { return self_type( !this->v_ ); }
operator +() const70     self_type  operator +() const  { return self_type( +this->v_ ); }
operator -() const71     self_type  operator -() const  { return self_type( -this->v_ ); }
72 
operator <(self_type const & r) const73     bool  operator  <( self_type const &r ) const  { return this->v_ < r.v_; }
operator ==(self_type const & r) const74     bool  operator ==( self_type const &r ) const  { return this->v_ == r.v_; }
75 
operator *=(self_type const & r)76     self_type &operator *=(self_type const &r) {this->v_ *= r.v_; return *this;}
operator /=(self_type const & r)77     self_type &operator /=(self_type const &r) {this->v_ /= r.v_; return *this;}
operator %=(self_type const & r)78     self_type &operator %=(self_type const &r) {this->v_ %= r.v_; return *this;}
operator +=(self_type const & r)79     self_type &operator +=(self_type const &r) {this->v_ += r.v_; return *this;}
operator -=(self_type const & r)80     self_type &operator -=(self_type const &r) {this->v_ -= r.v_; return *this;}
operator <<=(self_type const & r)81     self_type &operator<<=(self_type const &r){this->v_ <<= r.v_; return *this;}
operator >>=(self_type const & r)82     self_type &operator>>=(self_type const &r){this->v_ >>= r.v_; return *this;}
operator &=(self_type const & r)83     self_type &operator &=(self_type const &r) {this->v_ &= r.v_; return *this;}
operator |=(self_type const & r)84     self_type &operator |=(self_type const &r) {this->v_ |= r.v_; return *this;}
operator ^=(self_type const & r)85     self_type &operator ^=(self_type const &r) {this->v_ ^= r.v_; return *this;}
86 
87     // Input & output
operator >>(std::istream & i,self_type & x)88     friend std::istream & operator >>( std::istream &i, self_type &x )
89     { return i >> x.v_; }
90 
operator <<(std::ostream & o,self_type const & x)91     friend std::ostream & operator <<( std::ostream &o, self_type const &x )
92     { return o << x.v_; }
93 
94 };  // my_wrapped_integer
95 
96 template < typename IntType, int ID >
abs(my_wrapped_integer<IntType,ID> const & x)97 my_wrapped_integer<IntType, ID>  abs( my_wrapped_integer<IntType, ID> const &x )
98 { return ( x < my_wrapped_integer<IntType, ID>(0) ) ? -x : +x; }
99 
100 typedef my_wrapped_integer<int>          MyInt1;
101 typedef my_wrapped_integer<unsigned>     MyUnsigned1;
102 typedef my_wrapped_integer<int, 1>       MyInt2;
103 typedef my_wrapped_integer<unsigned, 1>  MyUnsigned2;
104 
105 // Without these explicit instantiations, MSVC++ 6.5/7.0 does not find
106 // some friend operators in certain contexts.
107 MyInt1       dummy1;
108 MyUnsigned1  dummy2;
109 MyInt2       dummy3;
110 MyUnsigned2  dummy4;
111 
112 // Various types to test with each GCD/LCM
113 typedef ::boost::mpl::list<signed char, short, int, long,
114 #ifdef BOOST_HAS_LONG_LONG
115  boost::long_long_type,
116 #elif defined(BOOST_HAS_MS_INT64)
117  __int64,
118 #endif
119  MyInt1>  signed_test_types;
120 typedef ::boost::mpl::list<unsigned char, unsigned short, unsigned,
121  unsigned long,
122 #ifdef BOOST_HAS_LONG_LONG
123  boost::ulong_long_type,
124 #elif defined(BOOST_HAS_MS_INT64)
125  unsigned __int64,
126 #endif
127  MyUnsigned1, MyUnsigned2>  unsigned_test_types;
128 
129 }  // namespace
130 
131 #define BOOST_NO_MACRO_EXPAND /**/
132 
133 // Specialize numeric_limits for _some_ of our types
134 namespace std
135 {
136 
137 template < >
138 class numeric_limits< MyInt1 >
139 {
140     typedef MyInt1::int_type             int_type;
141     typedef numeric_limits<int_type>  limits_type;
142 
143 public:
144     BOOST_STATIC_CONSTANT(bool, is_specialized = limits_type::is_specialized);
145 
BOOST_NO_MACRO_EXPAND()146     static MyInt1 min BOOST_NO_MACRO_EXPAND() throw()  { return (limits_type::min)(); }
BOOST_NO_MACRO_EXPAND()147     static MyInt1 max BOOST_NO_MACRO_EXPAND() throw()  { return (limits_type::max)(); }
148 
149     BOOST_STATIC_CONSTANT(int, digits      = limits_type::digits);
150     BOOST_STATIC_CONSTANT(int, digits10    = limits_type::digits10);
151 #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
152     BOOST_STATIC_CONSTANT(int, max_digits10    = limits_type::max_digits10);
153 #endif
154     BOOST_STATIC_CONSTANT(bool, is_signed  = limits_type::is_signed);
155     BOOST_STATIC_CONSTANT(bool, is_integer = limits_type::is_integer);
156     BOOST_STATIC_CONSTANT(bool, is_exact   = limits_type::is_exact);
157     BOOST_STATIC_CONSTANT(int, radix       = limits_type::radix);
epsilon()158     static MyInt1 epsilon() throw()      { return limits_type::epsilon(); }
round_error()159     static MyInt1 round_error() throw()  { return limits_type::round_error(); }
160 
161     BOOST_STATIC_CONSTANT(int, min_exponent   = limits_type::min_exponent);
162     BOOST_STATIC_CONSTANT(int, min_exponent10 = limits_type::min_exponent10);
163     BOOST_STATIC_CONSTANT(int, max_exponent   = limits_type::max_exponent);
164     BOOST_STATIC_CONSTANT(int, max_exponent10 = limits_type::max_exponent10);
165 
166     BOOST_STATIC_CONSTANT(bool, has_infinity             = limits_type::has_infinity);
167     BOOST_STATIC_CONSTANT(bool, has_quiet_NaN            = limits_type::has_quiet_NaN);
168     BOOST_STATIC_CONSTANT(bool, has_signaling_NaN        = limits_type::has_signaling_NaN);
169     BOOST_STATIC_CONSTANT(float_denorm_style, has_denorm = limits_type::has_denorm);
170     BOOST_STATIC_CONSTANT(bool, has_denorm_loss          = limits_type::has_denorm_loss);
171 
infinity()172     static MyInt1 infinity() throw()      { return limits_type::infinity(); }
quiet_NaN()173     static MyInt1 quiet_NaN() throw()     { return limits_type::quiet_NaN(); }
signaling_NaN()174     static MyInt1 signaling_NaN() throw() {return limits_type::signaling_NaN();}
denorm_min()175     static MyInt1 denorm_min() throw()    { return limits_type::denorm_min(); }
176 
177     BOOST_STATIC_CONSTANT(bool, is_iec559  = limits_type::is_iec559);
178     BOOST_STATIC_CONSTANT(bool, is_bounded = limits_type::is_bounded);
179     BOOST_STATIC_CONSTANT(bool, is_modulo  = limits_type::is_modulo);
180 
181     BOOST_STATIC_CONSTANT(bool, traps                    = limits_type::traps);
182     BOOST_STATIC_CONSTANT(bool, tinyness_before          = limits_type::tinyness_before);
183     BOOST_STATIC_CONSTANT(float_round_style, round_style = limits_type::round_style);
184 
185 };  // std::numeric_limits<MyInt1>
186 
187 template < >
188 class numeric_limits< MyUnsigned1 >
189 {
190     typedef MyUnsigned1::int_type        int_type;
191     typedef numeric_limits<int_type>  limits_type;
192 
193 public:
194     BOOST_STATIC_CONSTANT(bool, is_specialized = limits_type::is_specialized);
195 
BOOST_NO_MACRO_EXPAND()196     static MyUnsigned1 min BOOST_NO_MACRO_EXPAND() throw()  { return (limits_type::min)(); }
BOOST_NO_MACRO_EXPAND()197     static MyUnsigned1 max BOOST_NO_MACRO_EXPAND() throw()  { return (limits_type::max)(); }
198 
199     BOOST_STATIC_CONSTANT(int, digits      = limits_type::digits);
200     BOOST_STATIC_CONSTANT(int, digits10    = limits_type::digits10);
201 #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
202     BOOST_STATIC_CONSTANT(int, max_digits10    = limits_type::max_digits10);
203 #endif
204     BOOST_STATIC_CONSTANT(bool, is_signed  = limits_type::is_signed);
205     BOOST_STATIC_CONSTANT(bool, is_integer = limits_type::is_integer);
206     BOOST_STATIC_CONSTANT(bool, is_exact   = limits_type::is_exact);
207     BOOST_STATIC_CONSTANT(int, radix       = limits_type::radix);
epsilon()208     static MyUnsigned1 epsilon() throw()      { return limits_type::epsilon(); }
round_error()209     static MyUnsigned1 round_error() throw(){return limits_type::round_error();}
210 
211     BOOST_STATIC_CONSTANT(int, min_exponent   = limits_type::min_exponent);
212     BOOST_STATIC_CONSTANT(int, min_exponent10 = limits_type::min_exponent10);
213     BOOST_STATIC_CONSTANT(int, max_exponent   = limits_type::max_exponent);
214     BOOST_STATIC_CONSTANT(int, max_exponent10 = limits_type::max_exponent10);
215 
216     BOOST_STATIC_CONSTANT(bool, has_infinity             = limits_type::has_infinity);
217     BOOST_STATIC_CONSTANT(bool, has_quiet_NaN            = limits_type::has_quiet_NaN);
218     BOOST_STATIC_CONSTANT(bool, has_signaling_NaN        = limits_type::has_signaling_NaN);
219     BOOST_STATIC_CONSTANT(float_denorm_style, has_denorm = limits_type::has_denorm);
220     BOOST_STATIC_CONSTANT(bool, has_denorm_loss          = limits_type::has_denorm_loss);
221 
infinity()222     static MyUnsigned1 infinity() throw()    { return limits_type::infinity(); }
quiet_NaN()223     static MyUnsigned1 quiet_NaN() throw()  { return limits_type::quiet_NaN(); }
signaling_NaN()224     static MyUnsigned1 signaling_NaN() throw()
225         { return limits_type::signaling_NaN(); }
denorm_min()226     static MyUnsigned1 denorm_min() throw(){ return limits_type::denorm_min(); }
227 
228     BOOST_STATIC_CONSTANT(bool, is_iec559  = limits_type::is_iec559);
229     BOOST_STATIC_CONSTANT(bool, is_bounded = limits_type::is_bounded);
230     BOOST_STATIC_CONSTANT(bool, is_modulo  = limits_type::is_modulo);
231 
232     BOOST_STATIC_CONSTANT(bool, traps                    = limits_type::traps);
233     BOOST_STATIC_CONSTANT(bool, tinyness_before          = limits_type::tinyness_before);
234     BOOST_STATIC_CONSTANT(float_round_style, round_style = limits_type::round_style);
235 
236 };  // std::numeric_limits<MyUnsigned1>
237 
238 #if BOOST_WORKAROUND(BOOST_MSVC,<1300)
239 // MSVC 6.0 lacks operator<< for __int64, see
240 // http://support.microsoft.com/default.aspx?scid=kb;en-us;168440
241 
operator <<(ostream & os,__int64 i)242 inline ostream& operator<<(ostream& os, __int64 i)
243 {
244     char buf[20];
245     sprintf(buf,"%I64d", i);
246     os << buf;
247     return os;
248 }
249 
operator <<(ostream & os,unsigned __int64 i)250 inline ostream& operator<<(ostream& os, unsigned __int64 i)
251 {
252     char buf[20];
253     sprintf(buf,"%I64u", i);
254     os << buf;
255     return os;
256 }
257 #endif
258 
259 }  // namespace std
260 
261 // GCD tests
262 BOOST_AUTO_TEST_SUITE( gcd_test_suite )
263 
264 // GCD on signed integer types
BOOST_AUTO_TEST_CASE_TEMPLATE(gcd_int_test,T,signed_test_types)265 BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_int_test, T, signed_test_types )
266 {
267 #ifndef BOOST_MSVC
268     using boost::math::gcd;
269 #else
270     using namespace boost::math;
271 #endif
272 
273     // Originally from Boost.Rational tests
274     BOOST_CHECK_EQUAL( gcd<T>(  1,  -1), static_cast<T>( 1) );
275     BOOST_CHECK_EQUAL( gcd<T>( -1,   1), static_cast<T>( 1) );
276     BOOST_CHECK_EQUAL( gcd<T>(  1,   1), static_cast<T>( 1) );
277     BOOST_CHECK_EQUAL( gcd<T>( -1,  -1), static_cast<T>( 1) );
278     BOOST_CHECK_EQUAL( gcd<T>(  0,   0), static_cast<T>( 0) );
279     BOOST_CHECK_EQUAL( gcd<T>(  7,   0), static_cast<T>( 7) );
280     BOOST_CHECK_EQUAL( gcd<T>(  0,   9), static_cast<T>( 9) );
281     BOOST_CHECK_EQUAL( gcd<T>( -7,   0), static_cast<T>( 7) );
282     BOOST_CHECK_EQUAL( gcd<T>(  0,  -9), static_cast<T>( 9) );
283     BOOST_CHECK_EQUAL( gcd<T>( 42,  30), static_cast<T>( 6) );
284     BOOST_CHECK_EQUAL( gcd<T>(  6,  -9), static_cast<T>( 3) );
285     BOOST_CHECK_EQUAL( gcd<T>(-10, -10), static_cast<T>(10) );
286     BOOST_CHECK_EQUAL( gcd<T>(-25, -10), static_cast<T>( 5) );
287     BOOST_CHECK_EQUAL( gcd<T>(  3,   7), static_cast<T>( 1) );
288     BOOST_CHECK_EQUAL( gcd<T>(  8,   9), static_cast<T>( 1) );
289     BOOST_CHECK_EQUAL( gcd<T>(  7,  49), static_cast<T>( 7) );
290 }
291 
292 // GCD on unmarked signed integer type
BOOST_AUTO_TEST_CASE(gcd_unmarked_int_test)293 BOOST_AUTO_TEST_CASE( gcd_unmarked_int_test )
294 {
295 #ifndef BOOST_MSVC
296     using boost::math::gcd;
297 #else
298     using namespace boost::math;
299 #endif
300 
301     // The regular signed-integer GCD function performs the unsigned version,
302     // then does an absolute-value on the result.  Signed types that are not
303     // marked as such (due to no std::numeric_limits specialization) may be off
304     // by a sign.
305     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   1,  -1 )), MyInt2( 1) );
306     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(  -1,   1 )), MyInt2( 1) );
307     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   1,   1 )), MyInt2( 1) );
308     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(  -1,  -1 )), MyInt2( 1) );
309     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   0,   0 )), MyInt2( 0) );
310     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   7,   0 )), MyInt2( 7) );
311     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   0,   9 )), MyInt2( 9) );
312     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(  -7,   0 )), MyInt2( 7) );
313     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   0,  -9 )), MyInt2( 9) );
314     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(  42,  30 )), MyInt2( 6) );
315     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   6,  -9 )), MyInt2( 3) );
316     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>( -10, -10 )), MyInt2(10) );
317     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>( -25, -10 )), MyInt2( 5) );
318     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   3,   7 )), MyInt2( 1) );
319     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   8,   9 )), MyInt2( 1) );
320     BOOST_CHECK_EQUAL( abs(gcd<MyInt2>(   7,  49 )), MyInt2( 7) );
321 }
322 
323 // GCD on unsigned integer types
BOOST_AUTO_TEST_CASE_TEMPLATE(gcd_unsigned_test,T,unsigned_test_types)324 BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_unsigned_test, T, unsigned_test_types )
325 {
326 #ifndef BOOST_MSVC
327     using boost::math::gcd;
328 #else
329     using namespace boost::math;
330 #endif
331 
332     // Note that unmarked types (i.e. have no std::numeric_limits
333     // specialization) are treated like non/unsigned types
334     BOOST_CHECK_EQUAL( gcd<T>( 1u,   1u), static_cast<T>( 1u) );
335     BOOST_CHECK_EQUAL( gcd<T>( 0u,   0u), static_cast<T>( 0u) );
336     BOOST_CHECK_EQUAL( gcd<T>( 7u,   0u), static_cast<T>( 7u) );
337     BOOST_CHECK_EQUAL( gcd<T>( 0u,   9u), static_cast<T>( 9u) );
338     BOOST_CHECK_EQUAL( gcd<T>(42u,  30u), static_cast<T>( 6u) );
339     BOOST_CHECK_EQUAL( gcd<T>( 3u,   7u), static_cast<T>( 1u) );
340     BOOST_CHECK_EQUAL( gcd<T>( 8u,   9u), static_cast<T>( 1u) );
341     BOOST_CHECK_EQUAL( gcd<T>( 7u,  49u), static_cast<T>( 7u) );
342 }
343 
344 // GCD at compile-time
BOOST_AUTO_TEST_CASE(gcd_static_test)345 BOOST_AUTO_TEST_CASE( gcd_static_test )
346 {
347 #ifndef BOOST_MSVC
348     using boost::math::static_gcd;
349 #else
350     using namespace boost::math;
351 #endif
352 
353     // Can't use "BOOST_CHECK_EQUAL", otherwise the "value" member will be
354     // disqualified as compile-time-only constant, needing explicit definition
355     BOOST_CHECK( (static_gcd< 1,  1>::value) == 1 );
356     BOOST_CHECK( (static_gcd< 0,  0>::value) == 0 );
357     BOOST_CHECK( (static_gcd< 7,  0>::value) == 7 );
358     BOOST_CHECK( (static_gcd< 0,  9>::value) == 9 );
359     BOOST_CHECK( (static_gcd<42, 30>::value) == 6 );
360     BOOST_CHECK( (static_gcd< 3,  7>::value) == 1 );
361     BOOST_CHECK( (static_gcd< 8,  9>::value) == 1 );
362     BOOST_CHECK( (static_gcd< 7, 49>::value) == 7 );
363 }
364 
365 // TODO: non-built-in signed and unsigned integer tests, with and without
366 // numeric_limits specialization; polynominal tests; note any changes if
367 // built-ins switch to binary-GCD algorithm
368 
369 BOOST_AUTO_TEST_SUITE_END()
370 
371 
372 // LCM tests
BOOST_AUTO_TEST_SUITE(lcm_test_suite)373 BOOST_AUTO_TEST_SUITE( lcm_test_suite )
374 
375 // LCM on signed integer types
376 BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_int_test, T, signed_test_types )
377 {
378 #ifndef BOOST_MSVC
379     using boost::math::lcm;
380 #else
381     using namespace boost::math;
382 #endif
383 
384     // Originally from Boost.Rational tests
385     BOOST_CHECK_EQUAL( lcm<T>(  1,  -1), static_cast<T>( 1) );
386     BOOST_CHECK_EQUAL( lcm<T>( -1,   1), static_cast<T>( 1) );
387     BOOST_CHECK_EQUAL( lcm<T>(  1,   1), static_cast<T>( 1) );
388     BOOST_CHECK_EQUAL( lcm<T>( -1,  -1), static_cast<T>( 1) );
389     BOOST_CHECK_EQUAL( lcm<T>(  0,   0), static_cast<T>( 0) );
390     BOOST_CHECK_EQUAL( lcm<T>(  6,   0), static_cast<T>( 0) );
391     BOOST_CHECK_EQUAL( lcm<T>(  0,   7), static_cast<T>( 0) );
392     BOOST_CHECK_EQUAL( lcm<T>( -5,   0), static_cast<T>( 0) );
393     BOOST_CHECK_EQUAL( lcm<T>(  0,  -4), static_cast<T>( 0) );
394     BOOST_CHECK_EQUAL( lcm<T>( 18,  30), static_cast<T>(90) );
395     BOOST_CHECK_EQUAL( lcm<T>( -6,   9), static_cast<T>(18) );
396     BOOST_CHECK_EQUAL( lcm<T>(-10, -10), static_cast<T>(10) );
397     BOOST_CHECK_EQUAL( lcm<T>( 25, -10), static_cast<T>(50) );
398     BOOST_CHECK_EQUAL( lcm<T>(  3,   7), static_cast<T>(21) );
399     BOOST_CHECK_EQUAL( lcm<T>(  8,   9), static_cast<T>(72) );
400     BOOST_CHECK_EQUAL( lcm<T>(  7,  49), static_cast<T>(49) );
401 }
402 
403 // LCM on unmarked signed integer type
BOOST_AUTO_TEST_CASE(lcm_unmarked_int_test)404 BOOST_AUTO_TEST_CASE( lcm_unmarked_int_test )
405 {
406 #ifndef BOOST_MSVC
407     using boost::math::lcm;
408 #else
409     using namespace boost::math;
410 #endif
411 
412     // The regular signed-integer LCM function performs the unsigned version,
413     // then does an absolute-value on the result.  Signed types that are not
414     // marked as such (due to no std::numeric_limits specialization) may be off
415     // by a sign.
416     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   1,  -1 )), MyInt2( 1) );
417     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  -1,   1 )), MyInt2( 1) );
418     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   1,   1 )), MyInt2( 1) );
419     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  -1,  -1 )), MyInt2( 1) );
420     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   0,   0 )), MyInt2( 0) );
421     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   6,   0 )), MyInt2( 0) );
422     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   0,   7 )), MyInt2( 0) );
423     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  -5,   0 )), MyInt2( 0) );
424     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   0,  -4 )), MyInt2( 0) );
425     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  18,  30 )), MyInt2(90) );
426     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  -6,   9 )), MyInt2(18) );
427     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>( -10, -10 )), MyInt2(10) );
428     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(  25, -10 )), MyInt2(50) );
429     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   3,   7 )), MyInt2(21) );
430     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   8,   9 )), MyInt2(72) );
431     BOOST_CHECK_EQUAL( abs(lcm<MyInt2>(   7,  49 )), MyInt2(49) );
432 }
433 
434 // LCM on unsigned integer types
BOOST_AUTO_TEST_CASE_TEMPLATE(lcm_unsigned_test,T,unsigned_test_types)435 BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_unsigned_test, T, unsigned_test_types )
436 {
437 #ifndef BOOST_MSVC
438     using boost::math::lcm;
439 #else
440     using namespace boost::math;
441 #endif
442 
443     // Note that unmarked types (i.e. have no std::numeric_limits
444     // specialization) are treated like non/unsigned types
445     BOOST_CHECK_EQUAL( lcm<T>( 1u,   1u), static_cast<T>( 1u) );
446     BOOST_CHECK_EQUAL( lcm<T>( 0u,   0u), static_cast<T>( 0u) );
447     BOOST_CHECK_EQUAL( lcm<T>( 6u,   0u), static_cast<T>( 0u) );
448     BOOST_CHECK_EQUAL( lcm<T>( 0u,   7u), static_cast<T>( 0u) );
449     BOOST_CHECK_EQUAL( lcm<T>(18u,  30u), static_cast<T>(90u) );
450     BOOST_CHECK_EQUAL( lcm<T>( 3u,   7u), static_cast<T>(21u) );
451     BOOST_CHECK_EQUAL( lcm<T>( 8u,   9u), static_cast<T>(72u) );
452     BOOST_CHECK_EQUAL( lcm<T>( 7u,  49u), static_cast<T>(49u) );
453 }
454 
455 // LCM at compile-time
BOOST_AUTO_TEST_CASE(lcm_static_test)456 BOOST_AUTO_TEST_CASE( lcm_static_test )
457 {
458 #ifndef BOOST_MSVC
459     using boost::math::static_lcm;
460 #else
461     using namespace boost::math;
462 #endif
463 
464     // Can't use "BOOST_CHECK_EQUAL", otherwise the "value" member will be
465     // disqualified as compile-time-only constant, needing explicit definition
466     BOOST_CHECK( (static_lcm< 1,  1>::value) ==  1 );
467     BOOST_CHECK( (static_lcm< 0,  0>::value) ==  0 );
468     BOOST_CHECK( (static_lcm< 6,  0>::value) ==  0 );
469     BOOST_CHECK( (static_lcm< 0,  7>::value) ==  0 );
470     BOOST_CHECK( (static_lcm<18, 30>::value) == 90 );
471     BOOST_CHECK( (static_lcm< 3,  7>::value) == 21 );
472     BOOST_CHECK( (static_lcm< 8,  9>::value) == 72 );
473     BOOST_CHECK( (static_lcm< 7, 49>::value) == 49 );
474 }
475 
476 // TODO: see GCD to-do
477 
478 BOOST_AUTO_TEST_SUITE_END()
479