patterncppMinor
Finding prime divisors with wheel factorization
Viewed 0 times
withdivisorsfindingwheelprimefactorization
Problem
I am just starting to learn C++, and I wrote was the following implementation of the trial division algorithm to find the prime factors of a positive integer. I'm hoping the community here can suggest changes to both the algorithm and to the implementation. I barely know any language-specific features of C++, so I'm sure there is a lot of room for improvement.
In particular, I would like to be able to the following things:
In particular, I would like to be able to the following things:
- Work with larger integers than what
intallows.
- Catch errors arising from command-line arguments that cannot be parsed as
ints.
- Remove the hard-coding of the wheel and the cases of the first primes 2, 3, and 5.
- Improve general style/use more features of C++.
#include
/*
* Print out p as many times as it divides n.
* Return the quotient of n by the highest power of p dividing n.
*/
int checkdivisor(int n, int p) {
while (n % p == 0) {
std::cout 1) {
// Check 2, 3, and 5 individually
n = checkdivisor(n, 2);
n = checkdivisor(n, 3);
n = checkdivisor(n, 5);
// Start at the next potential prime divisor, 7.
int p = 7;
int i = 0;
while (n > 1) {
// If p^2 > n, then n is the last remaining prime divisor.
if (p * p > n) {
std::cout << n << std::endl;
return;
}
// Check if p is a prime divisor.
n = checkdivisor(n, p);
// Increment p based on the wheel.
p += WHEEL235[i++ % PERIOD];
}
}
}
/*
* Parse command-line arguments as ints (if possible), and print their prime
* factors.
*/
int main(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
primedivisors(std::stoi(argv[i]));
}
}Solution
Work with larger integers than what
Here, you seem to be asking for templates, so that your code works with any integer (and actually, any type which properly acts like an integer). I will convert the
Actually, it should even work with any type for which the operations
Catch errors arising from command-line arguments that cannot be parsed as
That one is easy if you look at the documentation of
int allowsHere, you seem to be asking for templates, so that your code works with any integer (and actually, any type which properly acts like an integer). I will convert the
checkdivisor function for you so that you can analyze it, then templating the rest of the code will be left as an exercice:template
Integer checkdivisor(Integer n, Integer p) {
while (n % p == 0) {
std::cout << p << std::endl;
n /= p;
}
return n;
}Actually, it should even work with any type for which the operations
%, / and == have the desired semantics.Catch errors arising from command-line arguments that cannot be parsed as
intsThat one is easy if you look at the documentation of
std::stoi: it says that std::stoi throws an std::invalid_argument exception if the string does not represent an integer and an std::out_of_range exception if the string to parse represents an integer too big for the type to hold. Knowing that, you can set up a simple try/catch to handle the errors:int main(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
try {
primedivisors(std::stoi(argv[i]));
}
catch (const std::invalid_argument& err) {
std::cerr << "the input is not an integer\n";
}
catch (const std::out_of_range& err) {
std::cerr << "the input is too big\n";
}
}
}Code Snippets
template<typename Integer>
Integer checkdivisor(Integer n, Integer p) {
while (n % p == 0) {
std::cout << p << std::endl;
n /= p;
}
return n;
}int main(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
try {
primedivisors(std::stoi(argv[i]));
}
catch (const std::invalid_argument& err) {
std::cerr << "the input is not an integer\n";
}
catch (const std::out_of_range& err) {
std::cerr << "the input is too big\n";
}
}
}Context
StackExchange Code Review Q#105088, answer score: 6
Revisions (0)
No revisions yet.