/////////////////////////////////////////////////////////////// // Copyright 2020 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #ifdef _MSC_VER #define _SCL_SECURE_NO_WARNINGS #endif #define BOOST_MP_GCD_DEBUG #include "test.hpp" #include #include #include #include // // clang in c++14 mode only has a problem with this file: it's an order of instantiation // issue caused by us using cpp_int within the gcd algorithm as an error check. // Just exclude that combination from testing for now as it's purely a testing issue // and we have other compilers that cover this sanity check... // #if !(defined(__clang__) && (__cplusplus > 201300)) using boost::multiprecision::cpp_int; std::tuple, std::vector, std::vector >& get_test_vector(std::size_t bits) { static std::map, std::vector, std::vector > > data; std::tuple, std::vector, std::vector >& result = data[bits]; if (std::get<0>(result).size() == 0) { boost::random::mt19937 mt; boost::random::uniform_int_distribution ui(cpp_int(1) << (bits - 1), cpp_int(1) << bits); std::vector& a = std::get<0>(result); std::vector& b = std::get<1>(result); std::vector& c = std::get<2>(result); for (unsigned i = 0; i < 1000; ++i) { a.push_back(ui(mt)); b.push_back(ui(mt)); if (b.back() > a.back()) b.back().swap(a.back()); c.push_back(0); } } return result; } std::vector& get_test_vector_a(std::size_t bits) { return std::get<0>(get_test_vector(bits)); } std::vector& get_test_vector_b(std::size_t bits) { return std::get<1>(get_test_vector(bits)); } std::vector& get_test_vector_c(std::size_t bits) { return std::get<2>(get_test_vector(bits)); } cpp_int gcd_euler(cpp_int u, cpp_int v) { while (v) { cpp_int t(v); v = u % v; u = t; } return u; } namespace boost { namespace multiprecision { namespace backends { std::size_t total_lehmer_gcd_calls = 0; std::size_t total_lehmer_gcd_bits_saved = 0; std::size_t total_lehmer_gcd_cycles = 0; }}} int main() { using boost::multiprecision::backends::total_lehmer_gcd_calls; using boost::multiprecision::backends::total_lehmer_gcd_bits_saved; using boost::multiprecision::backends::total_lehmer_gcd_cycles; unsigned bits = 2048; std::vector& a = get_test_vector_a(bits); std::vector& b = get_test_vector_b(bits); std::vector& c = get_test_vector_c(bits); for (unsigned i = 0; i < a.size(); ++i) { c[i] = gcd(a[i], b[i]); cpp_int t = gcd_euler(a[i], b[i]); BOOST_CHECK_EQUAL(t, c[i]); } float average_bits_saved_per_lehmer_call = static_cast(total_lehmer_gcd_bits_saved) / total_lehmer_gcd_calls; float average_number_of_euler_cycles_saved = static_cast(total_lehmer_gcd_cycles) / total_lehmer_gcd_calls; std::cout << "Average number of bits saved per Lehmer call: " << average_bits_saved_per_lehmer_call << std::endl; std::cout << "Average number of Euclid cycles saved per Lehmer call: " << average_number_of_euler_cycles_saved << std::endl; #ifndef BOOST_HAS_INT128 BOOST_CHECK_GT(average_bits_saved_per_lehmer_call, 30); #else BOOST_CHECK_GT(average_bits_saved_per_lehmer_call, 62); #endif return boost::report_errors(); } #else int main() { return 0; } #endif