2
0
mirror of https://github.com/boostorg/math.git synced 2026-02-01 08:32:15 +00:00
Files
math/test/modulo_test.cpp
2003-11-05 07:06:17 +00:00

207 lines
8.8 KiB
C++

// Boost modular arithmetic test program file ------------------------------//
// Copyright 2002 Daryle Walker. Use, modification, and distribution are
// subject to the Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
// See <http://www.boost.org/libs/math/> for the library's home page.
// Revision History
// 20 Sep 2002 Initial version (Daryle Walker)
#include <boost/config.hpp> // for BOOST_NO_MEMBER_TEMPLATES
#include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/math/modulo.hpp> // for boost::math::modulo, etc.
#include <boost/test/minimal.hpp> // for main, BOOST_TEST
#include <iomanip> // for std::setw
#include <ios> // for std::ios_base
#include <iostream> // for std::cout
#include <ostream> // for std::ostream, std::endl
#include <sstream> // for std::ostringstream, etc.
#include <string> // for std::string
// Control macro
#ifndef CONTROL_BACKWARD_CONVERSION_TEST
#define CONTROL_BACKWARD_CONVERSION_TEST 0
#endif
// Macros to compact code
#define PRIVATE_PRINT_UNARY_TABLE( Modulus, Op, Stream ) do { \
typedef ::boost::math::modulo< (Modulus) > modulo_type; \
(Stream) << "Unary Operation mod-" << (Modulus) \
<< " (" << #Op << " Value):\n"; \
for ( unsigned i = 0u ; i < (Modulus) ; ++i ) \
(Stream) << ' ' << ::std::setw(6) << i; \
(Stream) << '\n'; \
for ( unsigned j = 0u ; j < (Modulus) ; ++j ) \
(Stream) << ' ' << ::std::setw(6) << ( Op modulo_type(j) ); \
(Stream) << '\n' << ::std::endl; } while (false)
#define PRIVATE_PRINT_ALL_UNARY_TABLES( Modulus, Stream ) do { \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), +, (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), -, (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), ~, (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), (bool), (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), !, (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), ++, (Stream) ); \
PRIVATE_PRINT_UNARY_TABLE( (Modulus), --, (Stream) ); } while (false)
#define PRIVATE_PRINT_BINARY_TABLE( Modulus, Op, Stream ) do { \
typedef ::boost::math::modulo< (Modulus) > modulo_type; \
(Stream) << "Binary Operation mod-" << (Modulus) \
<< " (Left " << #Op << " Top):\n"; \
(Stream) << ::std::setw(6) << ' '; \
for ( unsigned i = 0u ; i < (Modulus) ; ++i ) \
(Stream) << ' ' << ::std::setw(6) << i; \
(Stream) << '\n'; \
for ( unsigned j = 0u ; j < (Modulus) ; ++j ) { \
(Stream) << ::std::setw(6) << j; \
for ( unsigned k = 0u ; k < (Modulus) ; ++k ) { \
::std::ostringstream oss; \
::std::string answer; \
oss.copyfmt( (Stream) ); \
try { oss << ( modulo_type(j) Op modulo_type(k) ); \
answer = oss.str(); } catch (...) { answer.assign( "-" ); } \
(Stream) << ' ' << ::std::setw(6) << answer; \
} (Stream) << '\n'; \
} (Stream) << ::std::endl; } while (false)
#define PRIVATE_PRINT_ALL_BINARY_TABLES( Modulus, Stream ) do { \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), +, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), -, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), *, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), /, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), &, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), |, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), ^, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), &&, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), ||, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), ==, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), !=, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), >=, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), <=, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), >, (Stream) ); \
PRIVATE_PRINT_BINARY_TABLE( (Modulus), <, (Stream) ); } while (false)
#define PRIVATE_PRINT_BINARY_FUNC_TABLE( Modulus, Func, Stream ) do { \
typedef ::boost::math::modulo< (Modulus) > modulo_type; \
(Stream) << "Binary Operation mod-" << (Modulus) \
<< " " << #Func << "(Left, Top):\n"; \
(Stream) << ::std::setw(6) << ' '; \
for ( unsigned i = 0u ; i < (Modulus) ; ++i ) \
(Stream) << ' ' << ::std::setw(6) << i; \
(Stream) << '\n'; \
for ( unsigned j = 0u ; j < (Modulus) ; ++j ) { \
(Stream) << ::std::setw(6) << j; \
for ( unsigned k = 0u ; k < (Modulus) ; ++k ) { \
::std::ostringstream oss; \
::std::string answer; \
oss.copyfmt( (Stream) ); \
try { oss << (Func)( modulo_type(j), k ); \
answer = oss.str(); } catch (...) { answer.assign( "-" ); } \
(Stream) << ' ' << ::std::setw(6) << answer; \
} (Stream) << '\n'; \
} (Stream) << ::std::endl; } while (false)
#define PRIVATE_PRINT_ALL_TABLES( Modulus, Stream ) do { \
PRIVATE_PRINT_ALL_UNARY_TABLES( (Modulus), (Stream) ); \
PRIVATE_PRINT_ALL_BINARY_TABLES( (Modulus), (Stream) ); } while (false)
// Main testing function
int
test_main
(
int , // "argc" is unused
char * [] // "argv" is unused
)
{
using boost::math::modulo;
using std::cout;
using boost::math::pow;
using std::endl;
typedef modulo<6> modulo6_t;
typedef modulo<3> modulo3_t;
// Try out most of the operations
cout.setf( std::ios_base::boolalpha );
PRIVATE_PRINT_ALL_TABLES( 7, cout );
PRIVATE_PRINT_BINARY_FUNC_TABLE( 7, pow, cout );
// Test input
std::istringstream as( "[3]" ), bs( "[2]" ), cs( "-4" );
modulo6_t a, b, c;
cout << "Doing input tests." << endl;
BOOST_TEST( as >> a );
BOOST_TEST( residue(a) == 3 );
BOOST_TEST( bs >> b );
BOOST_TEST( residue(b) == 2 );
BOOST_TEST( !(cs >> c) );
BOOST_TEST( (cs.clear(), cs.str( "[ty" ), !( cs >> c )) );
BOOST_TEST( (cs.clear(), cs.str( "[5?" ), !( cs >> c )) );
BOOST_TEST( (cs.clear(), cs.str( "[1]r0]]" ), ( cs >> c )) );
BOOST_TEST( residue(c) == 1 );
// Test post-(in/de)crement
cout << "Doing post-(in/de)crement tests." << endl;
BOOST_TEST( (c++, residue( c ) == 2) );
BOOST_TEST( (c--, residue( c ) == 1) );
// Test swap
cout << "Doing swap test." << endl;
swap( a, b );
BOOST_TEST( (residue( a ) == 2) && (residue( b ) == 3) );
#ifndef BOOST_NO_MEMBER_TEMPLATES
// Test cross-conversions
cout << "Doing cross-conversion tests." << endl;
BOOST_TEST( residue(modulo3_t( modulo6_t(0) )) == 0 );
BOOST_TEST( residue(modulo3_t( modulo6_t(1) )) == 1 );
BOOST_TEST( residue(modulo3_t( modulo6_t(2) )) == 2 );
BOOST_TEST( residue(modulo3_t( modulo6_t(3) )) == 0 );
BOOST_TEST( residue(modulo3_t( modulo6_t(4) )) == 1 );
BOOST_TEST( residue(modulo3_t( modulo6_t(5) )) == 2 );
#if CONTROL_BACKWARD_CONVERSION_TEST
// Should cause an error #if compiled
BOOST_TEST( residue(modulo6_t( modulo3_t(5) )) == 2 );
#endif
#endif
// Test quasi-traditional notation
cout << "Doing cross-comparison tests." << endl;
BOOST_TEST( 17 == modulo<5>(2) );
BOOST_TEST( 5 != modulo<2>(0) );
BOOST_TEST( modulo<5>(3) != 17 );
BOOST_TEST( modulo<2>(1) == 5 );
// Test assignment
cout << "Doing assignment tests." << endl;
BOOST_TEST( (c.assign( 4 ), residue( c ) == 4) );
BOOST_TEST( (c.assign( 17 ), residue( c ) == 5) );
// Test inversion status
cout << "Doing invertibilty tests." << endl;
BOOST_TEST( !modulo6_t(0).is_invertible() );
BOOST_TEST( modulo6_t(1).is_invertible() );
BOOST_TEST( !modulo6_t(2).is_invertible() );
BOOST_TEST( !modulo6_t(3).is_invertible() );
BOOST_TEST( !modulo6_t(4).is_invertible() );
BOOST_TEST( modulo6_t(5).is_invertible() );
BOOST_TEST( !modulo3_t(0).is_invertible() );
BOOST_TEST( modulo3_t(1).is_invertible() );
BOOST_TEST( modulo3_t(2).is_invertible() );
// Test Chinese remainder theorem
cout << "Doing Chinese Remainder Theorem tests." << endl;
BOOST_TEST( boost::math::chinese_remainder(modulo<7>( 3 ), modulo<13>( 7 ))
== modulo<91>(59) );
return boost::exit_success;
}