// 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 #include #include #include #include #include #include #include #include using namespace boost::multiprecision; using namespace boost::random; template BOOST_MP_CXX14_CONSTEXPR Integer sqrt_old(const Integer& x, Integer& r) { // // This is slow bit-by-bit integer square root, see for example // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented // at some point. // Integer s = 0; if (x == 0) { r = 0; return s; } int g = msb(x); if (g == 0) { r = 1; return s; } Integer t = 0; r = x; g /= 2; bit_set(s, g); bit_set(t, 2 * g); r = x - t; --g; do { t = s; t <<= g + 1; bit_set(t, 2 * g); if (t <= r) { bit_set(s, g); r -= t; } --g; } while (g >= 0); return s; } template BOOST_MP_CXX14_CONSTEXPR Integer sqrt_old(const Integer& x) { Integer r(0); return sqrt_old(x, r); } template std::tuple, std::vector >& get_test_vector(unsigned bits) { static std::map, std::vector > > data; std::tuple, std::vector >& result = data[bits]; if (std::get<0>(result).size() == 0) { mt19937 mt; uniform_int_distribution ui(T(1) << (bits - 1), T(1) << bits); std::vector& a = std::get<0>(result); std::vector& b = std::get<1>(result); for (unsigned i = 0; i < 1000; ++i) { a.push_back(ui(mt)); b.push_back(0); } } return result; } template std::vector& get_test_vector_a(unsigned bits) { return std::get<0>(get_test_vector(bits)); } template std::vector& get_test_vector_b(unsigned bits) { return std::get<1>(get_test_vector(bits)); } template static void BM_sqrt_old(benchmark::State& state) { int bits = state.range(0); std::vector& a = get_test_vector_a(bits); std::vector& b = get_test_vector_b(bits); for (auto _ : state) { for (unsigned i = 0; i < a.size(); ++i) b[i] = sqrt_old(a[i]); } state.SetComplexityN(bits); } template static void BM_sqrt_current(benchmark::State& state) { int bits = state.range(0); std::vector& a = get_test_vector_a(bits); std::vector& b = get_test_vector_b(bits); for (auto _ : state) { for (unsigned i = 0; i < a.size(); ++i) b[i] = sqrt(a[i]); } state.SetComplexityN(bits); } constexpr unsigned lower_range = 512; constexpr unsigned upper_range = 1 << 15; BENCHMARK_TEMPLATE(BM_sqrt_old, cpp_int)->RangeMultiplier(2)->Range(lower_range, upper_range)->Unit(benchmark::kMillisecond)->Complexity(); BENCHMARK_TEMPLATE(BM_sqrt_current, cpp_int)->RangeMultiplier(2)->Range(lower_range, upper_range)->Unit(benchmark::kMillisecond)->Complexity(); BENCHMARK_TEMPLATE(BM_sqrt_current, mpz_int)->RangeMultiplier(2)->Range(lower_range, upper_range)->Unit(benchmark::kMillisecond)->Complexity(); BENCHMARK_MAIN();