From 75bcd5ee0de20f4aa2c46b7f4e4b665f3ff9257f Mon Sep 17 00:00:00 2001 From: hurchalla Date: Tue, 19 Apr 2022 10:21:02 -0700 Subject: [PATCH] improve interface for factoring to a vector --- README.md | 2 +- .../factoring/detail/impl_factorize.h | 4 +-- include/hurchalla/factoring/factorize.h | 28 +++++++++---------- test/test_factorize.cpp | 10 +++---- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index f7dc363..afece5b 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ It may help to see a simple [example](examples/example_without_cmake). The API consists of five header files in total (all the headers that are not under the *detail* folder). These files are the three general purpose files *factorize.h*, *is_prime.h*, *greatest_common_divisor.h*, and in the resource_intensive_api folder, the two special purpose files *factorize_intensive_uint32.h* and *IsPrimeIntensive.h*. Please view these files for their documentation. A quick summary of the functions is provided below; in all cases T is a template parameter of integral type. *hurchalla::factorize(T x, int& num_factors)*. Returns a std::array containing the factors of x. -*hurchalla::factorize_to_vector(T x)*. Returns a std::vector containing the factors of x. +*hurchalla::factorize(T x, std::vector& factors)*. Clears a std::vector and fills it with the factors of x. *hurchalla::greatest_common_divisor(T a, T b)*. Returns the greatest common divisor of a and b. *hurchalla::is_prime(T x)*. Returns true if x is prime. Otherwise returns false. diff --git a/include/hurchalla/factoring/detail/impl_factorize.h b/include/hurchalla/factoring/detail/impl_factorize.h index 2e8d342..1e6d26c 100644 --- a/include/hurchalla/factoring/detail/impl_factorize.h +++ b/include/hurchalla/factoring/detail/impl_factorize.h @@ -116,13 +116,12 @@ struct impl_factorize { template - static std::vector factorize_to_vector(T x, + static void factorize_to_vector(T x, std::vector& vec, const PrimalityFunctor& is_prime_mf) { static_assert(ut_numeric_limits::is_integer, ""); using U = typename extensible_make_unsigned::type; - std::vector vec; // The max possible vector size needed for factors is when all of them are 2 constexpr int max_num_factors = ut_numeric_limits::digits; vec.reserve(max_num_factors); @@ -147,7 +146,6 @@ struct impl_factorize { std::back_inserter(fva), static_cast(x), is_prime_mf); HPBC_POSTCONDITION(vec.size() > 0); HPBC_POSTCONDITION(vec.size() <= max_num_factors); - return vec; } }; // end struct impl_factorize diff --git a/include/hurchalla/factoring/factorize.h b/include/hurchalla/factoring/factorize.h index bc8e926..dfb15c8 100644 --- a/include/hurchalla/factoring/factorize.h +++ b/include/hurchalla/factoring/factorize.h @@ -81,33 +81,33 @@ factorize(T x, int& num_factors) } -// This version of factorize returns a std::vector (rather than a std::array). -// It may be preferable if you wish to save stack space, since vector is heap -// allocated. Note that if you used factorize(), the returned std::array for -// type T of uint32_t would take 128 bytes on the stack, uint64_t would take 512 -// bytes, and __uint128_t would take 2kb. +// This version of factorize takes a std::vector, which it clears of any +// existing elements and then fills with the factors of x. When this function +// returns, the size of the vector is the number of factors. +// Note that this version might be preferable to the array version of factorize +// if you wish to save stack space; vector is heap allocated but the array +// version needs memory on the stack for its returned array (for example with +// type T of uint64_t, the array needs 512 bytes on stack). // -// Returns a vector that contains all factors of x. The size of the vector is -// the number of factors. // T can be any integral type <= 128 bits. template -std::vector factorize_to_vector(T x) +void factorize(T x, std::vector& factors) { static_assert(ut_numeric_limits::is_integer, ""); static_assert(ut_numeric_limits::digits <= 128, ""); HPBC_PRECONDITION(x >= 2); // 0 and 1 do not have prime factorizations + factors.clear(); namespace hd = ::hurchalla::detail; - std::vector vec = hd::impl_factorize::factorize_to_vector( - x, hd::PollardRhoIsPrime()); - HPBC_POSTCONDITION(vec.size() > 0); + hd::impl_factorize::factorize_to_vector( + x, factors, hd::PollardRhoIsPrime()); + HPBC_POSTCONDITION(factors.size() > 0); // The max possible vector size needed for factors is when all of them are 2 constexpr int max_num_factors = ut_numeric_limits::digits; - HPBC_POSTCONDITION(vec.size() <= max_num_factors); + HPBC_POSTCONDITION(factors.size() <= max_num_factors); // all the factors multiplied together should == x - HPBC_POSTCONDITION(x == std::accumulate(vec.begin(), vec.end(), + HPBC_POSTCONDITION(x == std::accumulate(factors.begin(), factors.end(), static_cast(1), std::multiplies())); - return vec; } diff --git a/test/test_factorize.cpp b/test/test_factorize.cpp index 446d947..0f0d4c7 100644 --- a/test/test_factorize.cpp +++ b/test/test_factorize.cpp @@ -29,16 +29,14 @@ using namespace hurchalla; TEST(HurchallaFactoringFactorize, exhaustive_uint16_t) { using T = std::uint16_t; + std::vector factors; for (T x = ut_numeric_limits::max(); x >= 2; --x) { std::vector answer = factorize_bruteforce(x); std::sort(answer.begin(), answer.end()); - int num_factors; - auto arr = factorize(x, num_factors); - std::sort(arr.begin(), arr.begin()+num_factors); + factorize(x, factors); + std::sort(factors.begin(), factors.end()); SCOPED_TRACE(testing::Message() << "x == " << x); - EXPECT_TRUE(num_factors == static_cast(answer.size())); - EXPECT_TRUE(std::equal(arr.begin(), arr.begin()+num_factors, - answer.begin())); + EXPECT_TRUE(factors == answer); } }