I tried a code on a coding website to find the largest prime factor of a number and it's exceeding the time limit for the last test case where probably they are using a large prime number. Can you please help me to reduce the complexity of the following code?
int main()
{
long n;
long int lar, fact;
long int sqroot;
int flag;
cin >> n;
lar=2, fact=2;
sqroot = sqrt(n);
flag = 0;
while(n>1)
{
if((fact > sqroot) && (flag == 0)) //Checking only upto Square Root
{
cout << n << endl;
break;
}
if(n%fact == 0)
{
flag = 1;
lar = fact;
while(n%fact == 0)
n = n/fact;
}
fact++;
}
if(flag == 1) //Don't display if loop fact reached squareroot value
cout << lar << endl;
}
Here I've also taken care of the loop checking till Square Root value. Still, how can I reduce its complexity further?
You can speed things up (if not reduce the complexity) by supplying a hard-coded list of the first N primes to use for the initial values of fact, since using composite values of fact are a waste of time. After that, avoid the obviously composite values of fact (like even numbers).
You can reduce the number of tests by skipping even numbers larger than 2, and stopping sooner if you have found smaller factors. Here is a simpler and faster version:
int main() {
unsigned long long n, lar, fact, sqroot;
cin >> n;
lar = 0;
while (n && n % 2 == 0) {
lar = 2;
n /= 2;
}
fact = 3;
sqroot = sqrt(n);
while (fact <= sqroot) {
if (n % fact == 0) {
lar = fact;
do { n /= fact; } while (n % fact == 0);
sqroot = sqrt(n);
}
fact += 2;
}
if (lar < n)
lar = n;
cout << lar << endl;
return 0;
}
I am not sure how large the input numbers may become, using the larger type unsigned long long for these computations will get you farther than long. Using a precomputed array of primes would help further, but not by a large factor.
The better result I've obtained is using the function below (lpf5()). It's based on the primality() function (below) that uses the formulas 6k+1, 6k-1 to individuate prime numbers. All prime numbers >= 5 may be expressed in one of the forms p=k*6+1 or p=k*6-1 with k>0 (but not all the numbers having such a forms are primes). Developing these formulas we can see a sequence like the following:
k=1 5,7
k=2 11,13
k=3 17,19
k=4 23,25*
k=5 29,31
.
.
.
k=10 59,61
k=11 65*,67
k=12 71,73
...
5,7,11,13,17,19,23,25,29,31,...,59,61,65,67,71,73,...
We observe that the difference between the terms is alternatively 2 and 4. Such a results may be obtained also using simple math. Is obvious that the difference between k*6+1 and k*6-1 is 2. It's simple to note that the difference between k*6+1 and (k+1)*6-1 is 4.
The function primality(x) returns x when x is prime (or 0 - take care) and the first divisor occurs when x is not prime.
I think you may obtain a better result inlining the primality() function inside the lpf5() function.
I've also tried to insert a table with some primes (from 1 to 383 - the primes in the first 128 results of the indicated formulas) inside the primality function, but the speed difference is unappreciable.
Here the code:
#include <stdio.h>
#include <math.h>
typedef long long unsigned int uint64;
uint64 lpf5(uint64 x);
uint64 primality(uint64 x);
uint64 lpf5(uint64 x)
{
uint64 x_=x;
while ( (x_=primality(x))!=x)
x=x/x_;
return x;
}
uint64 primality(uint64 x)
{
uint64 div=7,f=2,q;
if (x<4 || x==5)
return x;
if (!(x&1))
return 2;
if (!(x%3))
return 3;
if (!(x%5))
return 5;
q=sqrt(x);
while(div<=q) {
if (!(x%div)) {
return div;
}
f=6-f;
div+=f;
}
return x;
}
int main(void) {
uint64 x,k;
do {
printf("Input long int: ");
if (scanf("%llu",&x)<1)
break;
printf("Largest Prime Factor: %llu\n",lpf5(x));
} while(x!=0);
return 0;
}
Related
I was trying this question.
The prime factors of 13195 are 5, 7, 13 and 29.What is the largest prime factor of the number 600851475143 ?
And I had written the following code:
#include<iostream>
#define num 600851475143
using namespace std;
int isprime(unsigned long long int n)
{
unsigned long long int c=0;
for(unsigned long long int i=2;i<n;i++)
{
if(n%i==0)
{
c++;
break;
}
}
if(c==0)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
unsigned long long int a,i,n=num;
while(n-- && n>1)
{
if(isprime(n)==1 && num%n==0)
{
cout<<n;
break;
}
}
return 0;
}
The problem occurring with the code is it is working for 13195 and other small values. But not getting any output for 600851475143. Can anyone explain why it is not working for large value and also tell the changes that should be made in these to get the correct output.
The below code snippets are from c (but should run quite nice with c++ as well):
#include <stdio.h>
#define uIntPrime unsigned long long int
#define uIntPrimeFormat "llu"
uIntPrime findSmallestPrimeFactor(uIntPrime num)
{
uIntPrime limit = num / 2 + 1;
for(uIntPrime i=2; i<limit; i++)
{
if((num % i) == 0)
{
return i;
}
}
return num;
}
uIntPrime findLargestPrimeFactor(uIntPrime num)
{
uIntPrime largestPrimeFactor = 1; // start with the smallest possible value
while (num > 1) {
uIntPrime primeFactor = findSmallestPrimeFactor(num);
if (primeFactor > largestPrimeFactor) largestPrimeFactor = primeFactor;
num = num / primeFactor;
}
return largestPrimeFactor;
}
How can this work?
(first function:) Counting the numbers up from 2 means you are starting with prime factors on the lower end. (Numbers that are non-prime when counting are just not working out as fraction-less divisors and at the same time their prime number factor components were already probed because they are lower.)
(second function:) If a valid factor is found then the factor is pulled out from the number in question. Thus the search for the now smallest prime in the pulled-out number can repeat. (The conditional might probably be superfluous due to lower numbers are found first anyway - but it might resemble a search pattern you are familiar with - like in a minimum/maximum/other-criteria search. I am now leaving it up to you to proof it right or wrong with testing with your own main routine.)
The stop condition is about having the last factor extracted means dividing the value by itself and getting a value of 1 for num.
(There is for sure still much space for speeding this up!)
I have a program like this: given a sequence of integers, find the biggest prime and its positon.
Example:
input:
9 // how many numbers
19 7 81 33 17 4 19 21 13
output:
19 // the biggest prime
1 7 // and its positon
So first I get the input, store it in an array, make a copy of that array and sort it (because I use a varible to keep track of the higest prime, and insane thing will happen if that was unsorted) work with every number of that array to check if it is prime, loop through it again to have the positon and print the result.
But the time is too slow, can I improve it?
My code:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
int numbersNotSorted[n];
int maxNum{0};
for (int i = 0; i < n; i++)
{
cin >> numbersNotSorted[i];
}
int numbersSorted[n];
for (int i = 0; i < n; i++)
{
numbersSorted[i] = numbersNotSorted[i];
}
sort(numbersSorted, numbersSorted + n);
for (int number = 0; number < n; number++)
{
int countNum{0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++)
{
if (numbersSorted[number] % i == 0)
countNum++;
}
if (countNum == 0)
{
maxNum = numbersSorted[number];
}
}
cout << maxNum << '\n';
for (int i = 0; i < n; i++)
{
if (numbersNotSorted[i] == maxNum)
cout << i + 1 << ' ';
}
}
If you need the biggest prime, sorting the array brings you no benefit, you'll need to check all the values stored in the array anyway.
Even if you implemented a fast sorting algorithm, the best averages you can hope for are O(N + k), so just sorting the array is actually more costly than looking for the largest prime in an unsorted array.
The process is pretty straight forward, check if the next value is larger than the current largest prime, and if so check if it's also prime, store the positions and/or value if it is, if not, check the next value, repeat until the end of the array.
θ(N) time compexity will be the best optimization possible given the conditions.
Start with a basic "for each number entered" loop:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n;
int newNumber;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
}
}
If the new number is smaller than the current largest prime, then it can be ignored.
int main() {
int n;
int newNumber;
int highestPrime;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
if(newNumber >= highestPrime) {
}
}
}
If the new number is equal to the highest prime, then you just need to store its position somewhere. I'm lazy, so:
int main() {
int n;
int newNumber;
int highestPrime;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
If the new number is larger than the current largest prime, then you need to figure out if it is a prime number, and if it is you need to reset the list and store its position, etc:
int main() {
int n;
int newNumber;
int highestPrime = 0;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
} else { // newNumber > highestPrime
if(isPrime(newNumber)) {
nextPosition = 0; // Reset the list
highestPrime = newNumber;
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
You'll also want something to display the results:
if(highestPrime > 0) {
for(nextPosition= 0; nextPosition < currentPosition; nextPosition++) {
cout << positionList[nextPosition];
}
}
Now; the only thing you're missing is an isPrime(int n) function. The fastest way to do that is to pre-calculate a "is/isn't prime" bitfield. It might look something like:
bool isPrime(int n) {
if(n & 1 != 0) {
n >>= 1;
if( primeNumberBitfield[n / 32] & (1 << (n % 32)) != 0) {
return true;
}
}
return false;
}
The problem here is that (for positive values in a 32-bit signed integer) you'll need 1 billion bits (or 128 MiB).
To avoid that you can use a much smaller bitfield for numbers up to sqrt(1 << 31) (which is only about 4 KiB); then if the number is too large for the bitfield you can use the bitfield to find prime numbers and check (with modulo) if they divide the original number evenly.
Note that Sieve of Eratosthenes ( https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes ) is an efficient way to generate that smaller bitfield (but is not efficient to use for a sparse population of larger numbers).
If you do it right, you'll probably create the illusion that it's instantaneous because almost all of the work will be done while a human is slowly typing the numbers in (and not left until after all of the numbers have been entered). For a very fast typist you'll have ~2 milliseconds between numbers, and (after the last number is entered) humans can't notice delays smaller than about 10 milliseconds.
But the time is too slow, can I improve it?
Below loop suffers from:
Why check smallest values first? Makes more sense to check largest values first to find the largest prime. Exit the for (... number..) loop early once a prime is found. This takes advantage of the work done by sort().
Once a candidate value is not a prime, quit testing for prime-ness.
.
// (1) Start for other end rather than as below
for (int number = 0; number < n; number++) {
int countNum {0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++) {
if (numbersSorted[number] % i == 0)
// (2) No point in continuing prime testing, Value is composite.
countNum++;
}
if (countNum == 0) {
maxNum = numbersSorted[number];
}
}
Corrections left for OP to implement.
Advanced: Prime testing is a deep subject and many optimizations (trivial and complex) exist that are better than OP's approach. Yet I suspect the above 2 improvement will suffice for OP.
Brittleness: Code does not well handle the case of no primes in the list or n <= 0.
i <= sqrt(numbersSorted[number]) is prone to FP issues leading to an incorrect results. Recommend i <= numbersSorted[number]/i).
Sorting is O(n * log n). Prime testing, as done here, is O(n * sqrt(n[i])). Sorting does not increase O() of the overall code when the square root of the max value is less than log of n. Sorting is worth doing if the result of the sort is used well.
Code fails if the largest value was 1 as prime test incorrectly identifies 1 as a prime.
Code fails if numbersSorted[number] < 0 due to sqrt().
Simply full-range int prime test:
bool isprime(int num) {
if (num % 2 == 0) return num == 2;
for (int divisor = 3; divisor <= num / divisor; divisor += 2) {
if (num % divisor == 0) return false;
}
return num > 1;
}
If you want to find the prime, don't go for sorting. You'll have to check for all the numbers present in the array then.
You can try this approach to do the same thing, but all within a lesser amount of time:
Step-1: Create a global function for detecting a prime number. Here's how you can approach this-
bool prime(int n)
{
int i, p=1;
for(i=2;i<=sqrt(n);i++) //note that I've iterated till the square root of n, to cut down on the computational time
{
if(n%i==0)
{
p=0;
break;
}
}
if(p==0)
return false;
else
return true;
}
Step-2: Now your main function starts. You take input from the user:
int main()
{
int n, i, MAX;
cout<<"Enter the number of elements: ";
cin>>n;
int arr[n];
cout<<"Enter the array elements: ";
for(i=0;i<n;i++)
cin>>arr[i];
Step-3: Note that I've declared a counter variable MAX. I initialize this variable as the first element of the array: MAX=arr[0];
Step-4: Now the loop for iterating the array. What I did was, I iterated through the array and at each element, I checked if the value is greater than or equal to the previous MAX. This will ensure, that the program does not check the values which are less than MAX, thus eliminating a part of the array and cutting down the time. I then nested another if statement, to check if the value is a prime or not. If both of these are satisfied, I set the value of MAX to the current value of the array:
for(i=0;i<n;i++)
{
if(arr[i]>=MAX) //this will check if the number is greater than the previous MAX number or not
{
if(prime(arr[i])) //if the previous condition satisfies, then only this block of code will run and check if it's a prime or not
MAX=arr[i];
}
}
What happens is this- The value of MAX changes to the max prime number of the array after every single loop.
Step-5: Then, after finally traversing the array, when the program finally comes out of the loop, MAX will have the largest prime number of the array stored in it. Print this value of MAX. Now for getting the positions where MAX happens, just iterate over the whole loop and check for the values that match MAX and print their positions:
for(i=0;i<n;i++)
{
if(arr[i]==MAX)
cout<<i+1<<" ";
}
I ran this code in Dev C++ 5.11 and the compilation time was 0.72s.
I would like to find the largest prime factor of a given number. After several attempts, I've enhanced the test to cope with rather big numbers (i.e. up to one billion in milliseconds). The problem is now if go beyond one billion, the execution time goes forever, so to speak. I wonder if I can do more improvements and reduce the execution time. I'm hoping for better execution time because in this link Prime Factors Calculator, the execution time is incredibly fast. My target number at this moment is 600851475143. The code is rather self-explanatory. Note: I've considered Sieve of Eratosthenes algorithm with no luck regarding the execution time.
#include <iostream>
#include <cmath>
bool isPrime(int n)
{
if (n==2)
return true;
if (n%2==0)
return false;
for (int i(3);i<=sqrt(n);i+=2) // ignore even numbers and go up to sqrt(n)
if (n%i==0)
return false;
return true;
}
int main()
{
int max(0);
long long target(600851475143);
if( target%2 == 0 )
max = 2;
for ( int i(3); i<target; i+=2 ){ // loop through odd numbers.
if( target%i == 0 ) // check for common factor
if( isPrime(i) ) // check for prime common factor
max = i;
}
std::cout << "The greatest prime common factor is " << max << "\n";
return 0;
}
One obvious optimization that I can see is:
for (int i(3);i<=sqrt(n);i+=2) // ignore even numbers and go up to sqrt(n)
instead of calculating sqrt everytime you can cache the result in a variable.
auto maxFactor = static_cast<int>sqrt(n);
for (int i(3); i <= maxFactor; i+=2);
The reason I believe this could lead to speed up is sqrt deals with floating point arithematic and compilers usually aren't generous in optimizing floating point arithematic. gcc has a special flag ffast-math to enable floating point optimizations explicitely.
For numbers upto the target range that you mentioned, you will need better algorithms. repeated divisioning should suffice.
Here is the code (http://ideone.com/RoAmHd) which hardly takes any time to finish:
int main() {
long long input = 600851475143;
long long mx = 0;
for (int x = 2; x <= input/x; ++x){
while(input%x==0) {input/=x; mx = x; }
}
if (input > 1){
mx = input;
}
cout << mx << endl;
return 0;
}
The idea behind repeated division is if a number is already a factor of p, it is also a factor of p^2, p^3, p^4..... So we keep eliminating factors so only prime factors remain that eventually get to divide the number.
You don't need a primality test. Try this algorithm:
function factors(n)
f := 2
while f * f <= n
if n % f == 0
output f
n := n / f
else
f := f + 1
output n
You don't need a primality test because the trial factors increase by 1 at each step, so any composite trial factors will have already been handled by their smaller constituent primes.
I'll leave it to you to implement in C++ with appropriate data types. This isn't the fastest way to factor integers, but it is sufficient for Project Euler 3.
for ( int i(3); i<target; i+=2 ){ // loop through odd numbers.
if( target%i == 0 ) // check for common factor
if( isPrime(i) ) // check for prime common factor
max = i;
It is the first two lines of this code, not primality checks, which take almost all time. You divide target to all numbers from 3 to target-1. This takes about target/2 divisions.
Besides, target is long long, while i is only int. It is possible that the size is too small, and you get an infinite loop.
Finally, this code does not calculate the greatest prime common factor. It calculate the greatest prime divisor of target, and does it very inefficiently. So what do you really need?
And it is a bad idea to call anything "max" in c++, because max is a standard function.
Here is my basic version:
int main() {
long long input = 600851475143L;
long long pMax = 0;
// Deal with prime 2.
while (input % 2 == 0) {
input /= 2;
pMax = 2;
}
// Deal with odd primes.
for (long long x = 3; x * x <= input; x += 2) {
while (input % x == 0) {
input /= x;
pMax = x;
}
}
// Check for unfactorised input - must be prime.
if (input > 1) {
pMax = input;
}
std::cout << "The greatest prime common factor is " << pMax << "\n";
return 0;
}
It might be possible to speed things up further by using a Newton-Raphson integer square root method to set up a (mostly) fixed limit for the loop. If available that would need a rewrite of the main loop.
long long limit = iSqrt(input)
for (long long x = 3; x <= limit; x += 2) {
if (input % x == 0) {
pMax = x;
do {
input /= x;
} while (input % x == 0);
limit = iSqrt(input); // Value of input changed so reset limit.
}
}
The square root is only calculated when a new factor is found and the value of input has changed.
Note that except for 2 and 3, all prime numbers are adjacent to multiples of 6.
The following code reduces the total number of iterations by:
Leveraging the fact mentioned above
Decreasing target every time a new prime factor is found
#include <iostream>
bool CheckFactor(long long& target,long long factor)
{
if (target%factor == 0)
{
do target /= factor;
while (target%factor == 0);
return true;
}
return false;
}
long long GetMaxFactor(long long target)
{
long long maxFactor = 1;
if (CheckFactor(target,2))
maxFactor = 2;
if (CheckFactor(target,3))
maxFactor = 3;
// Check only factors that are adjacent to multiples of 6
for (long long factor = 5, add = 2; factor*factor <= target; factor += add, add = 6-add)
{
if (CheckFactor(target,factor))
maxFactor = factor;
}
if (target > 1)
return target;
return maxFactor;
}
int main()
{
long long target = 600851475143;
std::cout << "The greatest prime factor of " << target << " is " << GetMaxFactor(target) << std::endl;
return 0;
}
I'm trying to find the largest prime factor of the number 600851475143. My code works for smaller numbers that I test (below 100). However when confronted with 600851475143, it returns 4370432, definitely not prime. Any ideas what could be wrong with my code?
#include <iostream>
#include <time.h>
#include <math.h>
using namespace std;
int main()
{
int num;
int largest;
int count;
cout<<"Please enter a number to have its Largest Prime Factor found"<<endl;
cin>>num;
num = 600851475143;
for (int factor = 1; factor <= num; factor++)
{
if (num % factor == 0)
{
count = 0;
for (int primetest=2; count == 0 && factor > primetest ; primetest++)
{
if (factor % primetest == 0)
count ++;
//endif
}
if (count == 0)
largest = factor;
//endif
}
}//endif
cout<<largest<<endl;
system("PAUSE");
}
num = 600851475143;
Integer overflow occurs here. The size of num is not large enough to contain the value which you've provided.
Use uint64_t.
#include <cstdint> //must include this!
uint64_t num = 600851475143;
Read this : cstdint
There are quite a few major problems with the code, so I want to show a better complete
solution. The main problem is that it has no input validation! Good code must be correct
on all inputs it does not reject. So I have now included proper reading and validation of
input. In this way you would have automatically caught the problem.
All major types need to have proper names! So I have introduce the typedef uint_type.
The compiler will also find out already at compile-time, if the input 60085147514 is
valid or not (though this now is also rejected at run-time). If the compiler warns,
then you need to use a bigger integer-type; however unsigned long is enough on all common
64-bit platforms (but not on common 32-bit platforms). If you need bigger integer types,
then now just one place has to be changed.
Your algorithm is horribly inefficient! All what is needed is to divide the number through
all factors found (as long as possible), and you are guaranteed to only encounter prime
numbers -- so no need to check for that. And also one only needs to consider factors up to
the square-root of the input. This all requires a bit of logic to think through -- see
the code.
Then your code violates the principle of locality: declare your variables where they are
needed, not somewhere else. You also included non-C++ headers, which furthermore were
not needed. The use of using-directives just obfuscates the code: you don't see anymore
where the components come from; and there is no need for them! I also introduced an
anonymous namespace, for the more prominent definitions.
Finally, I use a more compact coding-style (indentation by 2 spaces, brackets on the
same line, avoiding brackets if possible. Think about it: in this way you can see much
more at one glance, while with a bit of training it is also easier to read.
When compiled as shown, the compiler warns about largest_factor possibly used undefined.
This is not the case, and I opted here to consider that warning as empty.
Program LargestPrimeFactor.cpp:
// Compile with
// g++ -O3 -Wall -std=c++98 -pedantic -o LargestPrimeFactor LargestPrimeFactor.cpp
#include <string>
#include <iostream>
namespace {
const std::string program_name = "LargestPrimeFactor";
const std::string error_output = "ERROR[" + program_name + "]: ";
const std::string version_number = "0.1";
enum ErrorCodes { reading_error = 1, range_error = 2 };
typedef unsigned long uint_type;
const uint_type example = 600851475143; // compile-time warnings will show
// whether uint_type is sufficient
}
int main() {
uint_type number;
std::cout << "Please enter a number to have its largest prime factor found:"
<< std::endl;
std::cin >> number;
if (not std::cin) {
std::cerr << error_output << "Number not of the required unsigned integer"
" type.\n";
return reading_error;
}
if (number <= 1) {
std::cerr << error_output << "Number " << number << " has no largest prime"
" factor.\n";
return range_error;
}
const uint_type input = number;
uint_type largest_factor;
for (uint_type factor = 2; factor <= number/factor; ++factor)
if (number % factor == 0) {
largest_factor = factor;
do number /= factor; while (number % factor == 0);
}
if (number != 1) largest_factor = number;
std::cout << "The largest prime factor of " << input << " is " << largest_factor
<< ".\n";
}
And to offer a correction. Depending on your compiler you could try unsigned long and see if that could hold your answer. Try and write to cout and see if the variable holds the value you expect.
On another note, if you are trying to find the largest factor would it not be more efficient to count down from the highest possible factor?
You can declare your num variable as long long int.
long long int num;
This will avoid all the types of overflows occurring in your code!
C++ Program to find the largest prime factor of number.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
// A function to find largest prime factor
long long maxPrimeFactors(long long n)
{
// Initialize the maximum prime factor
// variable with the lowest one
long long maxPrime = -1;
// Print the number of 2s that divide n
while (n % 2 == 0) {
maxPrime = 2;
n >>= 1; // equivalent to n /= 2
}
// n must be odd at this point
while (n % 3 == 0) {
maxPrime = 3;
n=n/3;
}
// now we have to iterate only for integers
// who does not have prime factor 2 and 3
for (int i = 5; i <= sqrt(n); i += 6) {
while (n % i == 0) {
maxPrime = i;
n = n / i;
}
while (n % (i+2) == 0) {
maxPrime = i+2;
n = n / (i+2);
}
}
// This condition is to handle the case
// when n is a prime number greater than 4
if (n > 4)
maxPrime = n;
return maxPrime;
}
// Driver program to test above function
int main()
{
long long n = 15;
cout << maxPrimeFactors(n) << endl;
n = 25698751364526;
cout << maxPrimeFactors(n);
}
I have implemented Sieve of Eratosthenes to solve the SPOJ problem PRIME1. Though the output is fine, my submission exceeds the time limit. How can I reduce the run time?
int main()
{
vector<int> prime_list;
prime_list.push_back(2);
vector<int>::iterator c;
bool flag=true;
unsigned int m,n;
for(int i=3; i<=32000;i+=2)
{
flag=true;
float s = sqrt(static_cast<float>(i));
for(c=prime_list.begin();c<=prime_list.end();c++)
{
if(*c>s)
break;
if(i%(*c)==0)
{
flag=false;
break;
}
}
if(flag==true)
{
prime_list.push_back(i);
}
}
int t;
cin>>t;
for (int times = 0; times < t; times++)
{
cin>> m >> n;
if (t) cout << endl;
if (m < 2)
m=2;
unsigned int j;
vector<unsigned int> req_list;
for(j=m;j<=n;j++)
{
req_list.push_back(j);
}
vector<unsigned int>::iterator k;
flag=true;
int p=0;
for(j=m;j<=n;j++)
{
flag=true;
float s = sqrt(static_cast<float>(j));
for(c=prime_list.begin();c<=prime_list.end();c++)
{
if((*c)!=j)
{
if((*c)>s)
break;
if(j%(*c)==0)
{
flag=false;
break;
}
}
}
if(flag==false)
{
req_list.erase (req_list.begin()+p);
p--;
}
p++;
}
for(k=req_list.begin();k<req_list.end();k++)
{
cout<<*k;
cout<<endl;
}
}
}
Your code is slow because you did not implement the Sieve of Eratosthenes algorithm. The algorithm works that way:
1) Create an array with size n-1, representing the numbers 2 to n, filling it with boolean values true (true means that the number is prime; do not forget we start counting from number 2 i.e. array[0] is the number 2)
2) Initialize array[0] = false.
3) Current_number = 2;
3) Iterate through the array by increasing the index by Current_number.
4) Search for the first number (except index 0) with true value.
5) Current_number = index + 2;
6) Continue steps 3-5 until search is finished.
This algorithm takes O(nloglogn) time.
What you do actually takes alot more time (O(n^2)).
Btw in the second step (where you search for prime numbers between n and m) you do not have to check if those numbers are prime again, ideally you will have calculated them in the first phase of the algorithm.
As I see in the site you linked the main problem is that you can't actually create an array with size n-1, because the maximum number n is 10^9, causing memory problems if you do it with this naive way. This problem is yours :)
I'd throw out what you have and start over with a really simple implementation of a sieve, and only add more complexity if really needed. Here's a possible starting point:
#include <vector>
#include <iostream>
int main() {
int number = 32000;
std::vector<bool> sieve(number,false);
sieve[0] = true; // Not used for now,
sieve[1] = true; // but you'll probably need these later.
for(int i = 2; i<number; i++) {
if(!sieve[i]) {
std::cout << "\t" << i;
for (int temp = 2*i; temp<number; temp += i)
sieve[temp] = true;
}
}
return 0;
}
For the given range (up to 32000), this runs in well under a second (with output directed to a file -- to the screen it'll generally be slower). It's up to you from there though...
I am not really sure that you have implemented the sieve of Erasthotenes. Anyway a couple of things that could speed up to some extent your algorithm would be: Avoid multiple rellocations of the vector contents by preallocating space (lookup std::vector<>::reserve). The operation sqrt is expensive, and you can probably avoid it altogether by modifying the tests (stop when the x*x > y instead of checking x < sqrt(y).
Then again, you will get a much better improvement by revising the actual algorithm. From a cursory look it seems as if you are iterating over all candidates and for each one of them, trying to divide with all the known primes that could be factors. The sieve of Erasthotenes takes a single prime and discards all multiples of that prime in a single pass.
Note that the sieve does not perform any operation to test whether a number is prime, if it was not discarded before then it is a prime. Each not prime number is visited only once for each unique factor. Your algorithm on the other hand is processing every number many times (against the existing primes)
I think one way to slightly speed up your sieve is the prevention of using the mod operator in this line.
if(i%(*c)==0)
Instead of the (relatively) expensive mod operation, maybe if you iterated forward in your sieve with addition.
Honestly, I don't know if this is correct. Your code is difficult to read without comments and with single letter variable names.
The way I understand the problem is that you have to generate all primes in a range [m,n].
A way to do this without having to compute all primes from [0,n], because this is most likely what's slowing you down, is to first generate all the primes in the range [0,sqrt(n)].
Then use the result to sieve in the range [m,n]. To generate the initial list of primes, implement a basic version of the sieve of Eratosthenes (Pretty much just a naive implementation from the pseudo code in the Wikipedia article will do the trick).
This should enable you to solve the problem in very little time.
Here's a simple sample implementation of the sieve of Eratosthenes:
std::vector<unsigned> sieve( unsigned n ) {
std::vector<bool> v( limit, true ); //Will be used for testing numbers
std::vector<unsigned> p; //Will hold the prime numbers
for( unsigned i = 2; i < n; ++i ) {
if( v[i] ) { //Found a prime number
p.push_back(i); //Stuff it into our list
for( unsigned j = i + i; j < n; j += i ) {
v[i] = false; //Isn't a prime/Is composite
}
}
}
return p;
}
It returns a vector containing only the primes from 0 to n. Then you can use this to implement the method I mentioned. Now, I won't provide the implementation for you, but, you basically have to do the same thing as in the sieve of Eratosthenes, but instead of using all integers [2,n], you just use the result you found. Not sure if this is giving away too much?
Since the SPOJ problem in the original question doesn't specify that it has to be solved with the Sieve of Eratosthenes, here's an alternative solution based on this article. On my six year old laptop it runs in about 15 ms for the worst single test case (n-m=100,000).
#include <set>
#include <iostream>
using namespace std;
int gcd(int a, int b) {
while (true) {
a = a % b;
if(a == 0)
return b;
b = b % a;
if(b == 0)
return a;
}
}
/**
* Here is Rowland's formula. We define a(1) = 7, and for n >= 2 we set
*
* a(n) = a(n-1) + gcd(n,a(n-1)).
*
* Here "gcd" means the greatest common divisor. So, for example, we find
* a(2) = a(1) + gcd(2,7) = 8. The prime generator is then a(n) - a(n-1),
* the so-called first differences of the original sequence.
*/
void find_primes(int start, int end, set<int>* primes) {
int an; // a(n)
int anm1 = 7; // a(n-1)
int diff;
for (int n = start; n < end; n++) {
an = anm1 + gcd(n, anm1);
diff = an - anm1;
if (diff > 1)
primes->insert(diff);
anm1 = an;
}
}
int main() {
const int end = 100000;
const int start = 2;
set<int> primes;
find_primes(start, end, &primes);
ticks = GetTickCount() - ticks;
cout << "Found " << primes.size() << " primes:" << endl;
set<int>::iterator iter = primes.begin();
for (; iter != primes.end(); ++iter)
cout << *iter << endl;
}
Profile your code, find hotspots, eliminate them. Windows, Linux profiler links.