/////////////////////////////////////////////////////////////// // Copyright 2011 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ #define BOOST_CHRONO_HEADER_ONLY #ifdef _MSC_VER # define _SCL_SECURE_NO_WARNINGS #endif #if !defined(TEST_MPF) && !defined(TEST_MPZ) && \ !defined(TEST_CPP_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPQ) \ && !defined(TEST_TOMMATH) && !defined(TEST_TOMMATH_BOOST_RATIONAL) && !defined(TEST_MPZ_BOOST_RATIONAL)\ && !defined(TEST_FIXED_INT) # define TEST_MPF # define TEST_MPZ # define TEST_MPFR # define TEST_CPP_FLOAT # define TEST_MPQ # define TEST_TOMMATH # define TEST_FIXED_INT #ifdef _MSC_VER #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!") #endif #ifdef __GNUC__ #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!" #endif #endif #if defined(TEST_MPF) || defined(TEST_MPZ) || defined(TEST_MPQ) || defined(TEST_MPZ_BOOST_RATIONAL) #include #include #endif #ifdef TEST_CPP_FLOAT #include #endif #if defined(TEST_MPFR) #include #endif #if defined(TEST_TOMMATH) || defined(TEST_TOMMATH_BOOST_RATIONAL) #include #include #endif #if defined(TEST_FIXED_INT) #include #endif #include #include #include #include template struct stopwatch { typedef typename Clock::duration duration; stopwatch() { m_start = Clock::now(); } duration elapsed() { return Clock::now() - m_start; } void reset() { m_start = Clock::now(); } private: typename Clock::time_point m_start; }; unsigned bits_wanted; // for integer types template struct tester { tester() { a.assign(500, 0); for(int i = 0; i < 500; ++i) { b.push_back(generate_random()); c.push_back(generate_random()); small.push_back(gen()); } } double test_add() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] + c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_subtract() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] - c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_add_int() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] + 1; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_subtract_int() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] - 1; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_multiply() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] * c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_divide() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] / c[i] + b[i] / small[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_str() { stopwatch w; for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i].str(); return boost::chrono::duration_cast >(w.elapsed()).count(); } // // The following tests only work for ineteger types: // double test_mod() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] % c[i] + b[i] % small[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_or() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] | c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_and() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] & c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_xor() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] ^ c[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_complement() { stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = ~b[i]; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_left_shift() { int shift = std::numeric_limits::is_bounded ? std::numeric_limits::digits : bits_wanted; shift /= 2; stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] << shift; } return boost::chrono::duration_cast >(w.elapsed()).count(); } double test_right_shift() { int shift = std::numeric_limits::is_bounded ? std::numeric_limits::digits : bits_wanted; shift /= 2; stopwatch w; for(unsigned i = 0; i < 1000; ++i) { for(unsigned i = 0; i < b.size(); ++i) a[i] = b[i] >> shift; } return boost::chrono::duration_cast >(w.elapsed()).count(); } private: T generate_random() { return generate_random(boost::mpl::int_()); } T generate_random(const boost::mpl::int_&) { T val = gen(); T prev_val = -1; while(val != prev_val) { val *= (gen.max)(); prev_val = val; val += gen(); } int e; val = frexp(val, &e); typedef typename T::backend_type::exponent_type e_type; static boost::random::uniform_int_distribution ui(0, std::numeric_limits::max_exponent - 10); return ldexp(val, ui(gen)); } T generate_random(const boost::mpl::int_&) { typedef boost::random::mt19937::result_type random_type; T max_val; unsigned digits; if(std::numeric_limits::is_bounded) { max_val = (std::numeric_limits::max)(); digits = std::numeric_limits::digits; } else { max_val = T(1) << bits_wanted; digits = bits_wanted; } unsigned bits_per_r_val = std::numeric_limits::digits - 1; while((random_type(1) << bits_per_r_val) > (gen.max)()) --bits_per_r_val; unsigned terms_needed = digits / bits_per_r_val + 1; T val = 0; for(unsigned i = 0; i < terms_needed; ++i) { val *= (gen.max)(); val += gen(); } val %= max_val; return val; } std::vector a, b, c, small; static boost::random::mt19937 gen; }; template boost::random::mt19937 tester::gen; template void test_int_ops(tester& t, const char* type, unsigned precision, const boost::mpl::int_&) { std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "%" << t.test_mod() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "|" << t.test_or() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "&" << t.test_and() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "^" << t.test_xor() << std::endl; //std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "~" << t.test_complement() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "<<" << t.test_left_shift() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << ">>" << t.test_right_shift() << std::endl; } template void test_int_ops(tester& t, const char* type, unsigned precision, const U&) { } template void test(const char* type, unsigned precision) { bits_wanted = precision; tester::value> t; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "+" << t.test_add() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "-" << t.test_subtract() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "+ (int)" << t.test_add_int() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "- (int)" << t.test_subtract_int() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "*" << t.test_multiply() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "/" << t.test_divide() << std::endl; std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(5) << "str" << t.test_str() << std::endl; test_int_ops(t, type, precision, typename boost::multiprecision::number_category::type()); } int main() { #ifdef TEST_MPF test("gmp_float", 50); test("gmp_float", 100); test("gmp_float", 500); #endif #ifdef TEST_MPZ test("gmp_int", 64); test("gmp_int", 128); test("gmp_int", 256); test("gmp_int", 512); test("gmp_int", 1024); #endif #ifdef TEST_TOMMATH test("tommath_int", 64); test("tommath_int", 128); test("tommath_int", 256); test("tommath_int", 512); test("tommath_int", 1024); #endif #ifdef TEST_FIXED_INT test("mp_int64_t", 64); test("mp_int128_t", 128); test("mp_int256_t", 256); test("mp_int512_t", 512); test > >("mp_int1024_t", 1024); #endif #ifdef TEST_CPP_FLOAT test("cpp_float", 50); test("cpp_float", 100); test > >("cpp_float", 500); #endif #ifdef TEST_MPFR test("mpfr_float", 50); test("mpfr_float", 100); test("mpfr_float", 500); #endif return 0; }