How to optimize Sieve of Eratosthenes further - c#

I was solving Project Euler problem 10 and I was able to do so using the Sieve of Eratosthenes, but now I'd like to optimize the code a bit further.
Considering the fact that all prime numbers greater than 3 are of the form 6k+1 or 6k-1 I only set those values in the array as true, but not all numbers of that form will be prime, so I have to sieve through the values and remove the non primes, and my code is as follows:
public static bool[] GeneratePrimes(int bound)
{
bool[] isPrime = new bool[bound];
isPrime[2] = true;
isPrime[3] = true;
// Taking into account that all primes greater than 2 and 3
// Are of the form 6k+1 or 6k-1
for (int k = 6; k < isPrime.Length; k += 6)
{
if (k + 1 < isPrime.Length) isPrime[k + 1] = true;
isPrime[k - 1] = true;
}
// At this point we still have some numbers that aren't prime marked as prime
// So we go over them with a sieve, also we can start at 3 for obvious reasons
for (int i = 3; i * i <= bound; i += 2)
{
if (isPrime[i])
{
// Can this be optimized?
for (int j = i; j * i <= bound; j++)
isPrime[i * j] = false;
}
}
return isPrime;
}
}
So how can I optimize the code that I sieve through less numbers? For example if my number is 5, numbers such as 10,15,20 are already stroked through, but 25 for example isn't so is it possible to only go through values such is 25?

When eliminating multiples of a prime p, you only need to start from p * p. Any multiple of p below that will already have been eliminated as it has a smaller prime factor. This is the reason behind your comments about 5 and 25.

Paul Pritchard has done much work with wheel sieves that extend your 6k±1 idea to larger prime wheels. Google for "pritchard wheel sieve" or look at my blog to get started.

Related

Project Euler 1:Find the sum of all the multiples of 3 or 5 below 1000, works for 10 numbers but doesn't work for 1000 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
So I decided to try and solve some problems on Euler site to improve with programming. While trying to solve the first problem I wrote a quick code to count the sum and it worked for 10 numbers, but for 1000 it shows me the answer: 166833 which is wrong and I can't really find an issue here. If someone could give me a hint to improve my algorythm so it would work.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Multiplies_of_3_and_5
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[7000];
for (int j = 0; j<array.Length ;j++)
{
array[j] = j + 1;
}
int n = 1;
int z = 1;
int numbers = 0;
for (int i = 0; i<999; i++)
{
if (array[i] == 3 * n )
{
n++;
numbers += array[i];
}
else if (array[i] == 5 * z)
{
z++;
numbers += array[i];
}
}
Console.WriteLine(string.Join(" ", numbers));
Console.ReadLine();
}
}
}
Idea count 3s, 5s and deduct 15s as they are in both but only need counting once.
int maxNum = 999;
int num3s = maxNum/3; // rounded down 333
int num5s = maxNum/5; // rounded down 199
int num15s = maxNum/15; // rounded down 66
Knowing how many still isn't going to tell us the sum. Pythagoras to the rescue.
sum3s = 3+6+9+12+15 (=45)
sum5s = 5+10+15 (=30)
sum15s = 15 (=15)
average = (max+min)/2
Either there is an odd number of 3's, 5's or 15's and you get an even average. Or there is an even number in which case /2 and the even cancel each other.
So we get
sumXs = (min+max)*numXs
In the above case we get
sum3s = (3+15)/2*5 = 45
sum5s = (5+15)/2*3 = 30
sum15s = (15+15)/2*1 = 15
int sum = sum3s+sum5s-sum15s = 60;
Another example 11
sum = (3+9)/2*3 + (5+10)/2*2 - 0 = 33
And finally sum of 3s and 5s up to 999
sum = (3+999)/2*333 + (5+995)/2*199 - (15+990)/2*66
= 501*333 + 500*199 - (1005)*66/2
= 501*333 + 500*199 - 1005*33
= 166833 + 99500 - 33165
= 233168
Which is also the result of the programs.
You should read up on the modulo operator (%).
static void main(String[] args)
{
int sum = 0;
for(int i=1; i< 1000; i++){
if (i % 3 == 0 || i % 5 == 0){
sum += i;
}
}
Console.WriteLine(sum);
}
To give an explanation, the modulo operator gives the remainder when performing integer division on a value.
For example, 6 % 3 == 0 (3 evenly divides 6), 7 % 3 == 1 (7 divided by 3 leaves remainder 1).
So to sum all of the multiples of 3 and 5, just check if the value divides evenly by 3 or 5 (the if statement), and if so, add it to the running sum.
Note that your algorithm is going to screw up when you get to numbers that are multiple of 3 AND 5. You never add to z in that case. You also need to change it to be <= 999, not <999 (you will never add 999 in your code, which divides by 3).
To sum things up:
Use your loop variable directly, no need to pre-populate another
array or have separate values keeping track of what multiple you're
at.
Modulo is super useful.
When reaching 15, n will increase but z won't. Therefore the second branch ("is divideable by 5") won't trigger anymore.
You can either use flags for both and then use those flags to increase numbers, n and z or use modulo as suggested.
Enumerable.Range(1, 999).Sum(x => x % 3 == 0 || x % 5 == 0 ? x : 0);
After listening to tips from You I remade my code and it works just fine. But it is surely a pain to do it this way, so I suggest using (%) for that. Anyway I will post my code here as well. Thanks for help again!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Multiplies_of_3_and_5
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[7000];
for (int j = 0; j < array.Length; j++)
{
array[j] = j + 1;
}
int n = 1;
int z = 1;
int numbers = 0;
for (int i = 0; i < 999; i++)
{
if (array[i] == 3*n && array[i] == 5*z)
{
n++;
}
if (array[i] == 3 * n)
{
n++;
numbers += array[i];
}
if (array[i] == 5 * z)
{
z++;
numbers += array[i];
}
}
Console.WriteLine(string.Join(" ", numbers));
Console.ReadLine();
}
}
}

How to make this small C# program which calculates prime numbers using the Sieve of Eratosthenes as efficient and economical as possible?

I've made a small C# program which calculates prime numbers using the Sieve of Eratosthenes.
long n = 100000;
bool[] p = new bool[n+1];
for(long i=2; i<=n; i++)
{
p[i]=true;
}
for(long i=2; i<=X; i++)
{
for(long j=Y; j<=Z; j++)
{
p[i*j]=false;
}
}
for(long i=0; i<=n; i++)
{
if(p[i])
{
Console.Write(" "+i);
}
}
Console.ReadKey(true);
My question is: which X, Y and Z should I choose to make my program as efficient and economical as possible?
Of course we can just take:
X = n
Y = 2
Z = n
But then the program won't be very efficient.
It seems we can take:
X = Math.Sqrt(n)
Y = i
Z = n/i
And apparently the first 100 primes that the program gives are all correct.
There are several optimisations that can be applied without making the program overly complicated.
you can start the crossing out at j = i (effectively i * i instead of 2 * i) since all lower multiples of i have already been crossed out
you can save some work by leaving all even numbers out of the array (remembering to produce the prime 2 out of thin air when needed); hence array cell k represents the odd integer 2 * k + 1
you can make things faster by turning repeated multiplication (i * j) into iterated addition (k += i); instead of looping over j in the inner loop you loop (k = i * i; k <= N; k += i)
in some cases it can be advantageous to initialise the array with 0 (false) and set cells to 1 (true) for composites; its meaning is thus 'is_composite' instead of 'is_prime'
Harvesting all the low-hanging fruit, the loops thus become (in C++, but C# should be sort of similar):
uint32_t max_factor_bit = uint32_t(sqrt(double(n))) >> 1;
uint32_t max_bit = n >> 1;
for (uint32_t i = 3 >> 1; i <= max_factor_bit; ++i)
{
if (composite[i]) continue;
uint32_t n = (i << 1) + 1;
uint32_t k = (n * n) >> 1;
for ( ; k <= max_bit; k += n)
{
composite[k] = true;
}
}
Regarding the computation of max_factor there are some caveats where the compiler can bite you, for larger values of n. There's a topic for that on Code Review.
A further, easy optimisation is to represent the bitmap as an array of bytes, with each byte standing for eight odd integers. For setting bit k in byte array a you would do a[k / CHAR_BIT] |= (1 << (k % CHAR_BIT)) where CHAR_BIT is the number of bits in a byte. However, such bit trickery is normally wrapped into an inline function to keep the code clean. E.g. in C++ I tell the compiler how to generate such functions using a template like this:
template<typename word_t>
inline
void set_bit (word_t *p, uint32_t index)
{
enum { BITS_PER_WORD = sizeof(word_t) * CHAR_BIT };
// we can trust the compiler to use masking and shifting instead of division; we cannot do that
// ourselves without having the log2 which cannot easily be computed as a constexpr
p[index / BITS_PER_WORD] |= word_t(1) << (index % BITS_PER_WORD);
}
This allows me to say set_bit(a, k) for any type of array - byte, integer, whatever - without having to write special code or use invocations; it's basically a type-safe equivalent to the old C-style macros. I'm not certain whether something similar is possible in C#. There is, however, the C# type BitArray where all that stuff is already done for you under the hood.
On pastebin there's a small demo .cpp for the segmented Sieve of Eratosthenes, where two further optimisations are applied: presieving by small integers, and sieving in small, cache friendly blocks so that the full range of 32-bit integers can be sieved in 2 seconds flat. This could give you some inspiration...
When doing the Sieve of Eratosthenes, memory savings easily translate to speed gains because the algorithm is memory-intensive and it tends to stride all over the memory instead of accessing it locally. That's why space savings due to compact representation (only odd integers, packed bits - i.e. BitArray) and localisation of access (by sieving in small blocks instead of the whole array in one go) can speed up the code by one or more orders of magnitude, without making the code significantly more complicated.
It is possible to go far beyond the easy optimisations mentioned here, but that tends to make the code increasingly complicated. One word that often occurs in this context is the 'wheel', which can save a further 50% of memory space. The wiki has an explanation of wheels here, and in a sense the odds-only sieve is already using a 'modulo 2 wheel'. Conversely, a wheel is the extension of the odds-only idea to dropping further small primes from the array, like 3 and 5 in the famous 'mod 30' wheel with modulus 2 * 3 * 5. That wheel effectively stuffs 30 integers into one 8-bit byte.
Here's a runnable rendition of the above code in C#:
static uint max_factor32 (double n)
{
double r = System.Math.Sqrt(n);
if (r < uint.MaxValue)
{
uint r32 = (uint)r;
return r32 - ((ulong)r32 * r32 > n ? 1u : 0u);
}
return uint.MaxValue;
}
static void sieve32 (System.Collections.BitArray odd_composites)
{
uint max_bit = (uint)odd_composites.Length - 1;
uint max_factor_bit = max_factor32((max_bit << 1) + 1) >> 1;
for (uint i = 3 >> 1; i <= max_factor_bit; ++i)
{
if (odd_composites[(int)i]) continue;
uint p = (i << 1) + 1; // the prime represented by bit i
uint k = (p * p) >> 1; // starting point for striding through the array
for ( ; k <= max_bit; k += p)
{
odd_composites[(int)k] = true;
}
}
}
static int Main (string[] args)
{
int n = 100000000;
System.Console.WriteLine("Hello, Eratosthenes! Sieving up to {0}...", n);
System.Collections.BitArray odd_composites = new System.Collections.BitArray(n >> 1);
sieve32(odd_composites);
uint cnt = 1;
ulong sum = 2;
for (int i = 1; i < odd_composites.Length; ++i)
{
if (odd_composites[i]) continue;
uint prime = ((uint)i << 1) + 1;
cnt += 1;
sum += prime;
}
System.Console.WriteLine("\n{0} primes, sum {1}", cnt, sum);
return 0;
}
This does 10^8 in about a second, but for higher values of n it gets slow. If you want to do faster then you have to employ sieving in small, cache-sized blocks.

Project Euler Solution #14

I have the following problem (from ProjectEuler.net - Problem 14)
The following iterative sequence is defined for the set of positive integers:
n -> n/2 (n is even)
n -> 3n + 1 (n is odd)
Using the rule above and starting with 13, we generate the following sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
I used:
static int road (int n)
{
int road = 0;
while (n != 1)
{
if (n % 2 == 0)
n = n / 2;
else
n = 3 * n + 1;
road++;
}
return road;
}
static void Main(string[] args)
{
int max = 0, num = 0;
for (int i = 1; i < 1000000; i++)
{
if (road(i) > max)
{
max = road(i);
num = i;
}
}
Console.WriteLine(num);
}
But no output is printed.
(I'm not going to give you a complete solution since Project Euler is intended to make you think, not us who already solved the problems.)
Try figuring out how large the values in your chain are going to be and keep in mind the limits for integral types.
function problem14(){
function r(p,n){
return cl(p)>cl(n)?p:n;
}
function c(n){
return n%2===0?n/2:3*n+1;
}
function cl(n){
var _a = 1;
var _n = n;
while(_n !== 1){
_a++;
_n = c(_n);
}
return _a;
}
var b = [];
var m = 20;
var i = 500000;
while(i < 1000000){
var _n = cl(i);
if(_n>m){
b.push(i);
m = _n;
}
i++;
}
return b.reduce(r);
}
Here is my js code.
It is not that "nothing is output", it is just running very long. If you change the upper bound of the for-loop to 100000, you will see that pretty quickly you get output. The reason it runs very long is that you use unchecked integers and you don't get an overflowexception where you should want one. Break after a few seconds an you'll see a negative n.
Try the following , i.e. with the checked keyword, it will illustrate what I mean:
// will now throw OverflowException with large n
checked
{
int road = 0;
while (n != 1)
{
if (n%2 == 0)
n = n/2;
else
n = 3*n + 1;
road++;
}
return road;
}
First, note that you are calling the road() function twice per iteration, which is a waste of processing time (and for a 'function with side effects', could have unwanted consequences).
Secondly, due to integer overflow, you can't get an answer - the value 113383, for example, ends up cycling around the same 20 or so numbers
-122, -61, -182, -91, -272, -136, -68, -34, -17, -50, -25, -74, -37, -110, -55, ,-164, -82, -41, -122
Oops!

How do you generate a user defined amount of prime numbers?

I'm trying to generate prime numbers based on user input. This is what I have so far but I just can't seem to figure it out:
Console.Write("Please enter the number of prime numbers you would like to see:");
int numberOfPrimes = Convert.ToInt32(Console.ReadLine());
for (int x = 0; x < numberOfPrimes; x++)
{
for (int a = 2; a <= x ; ++a)
{
bool prime = true;
for (int b = 2; b < a; ++b)
{
if (a % b == 0)
{
prime = false;
}//end if
}//end double nested for
if (prime == true)
{
Console.WriteLine(a);
}//end if
}//end nested for
}//end for
You should be able to see why your results are wrong quite easily if you look at your loop structures. Step through them by hand (it won't take long).
The reason that you are getting your current results is that not every iteration of the outer loop (x < numberOfPrimes) produces a result - it will skip quite a few iterations due to the way the inner loop is structured.
What you really need to do is restructure the inner loops. Your innermost loop works fine, and should detect any prime numbers. Your second loop, however, should only test numbers that haven't yet been tested. Also, it should stop looping once you find a prime number.
You should structure your code better, it's really messy the way you do it now. Have a method IsPrime(int x) which returns true if x is prime and false otherwise.
Then, to generate numberOfPrimes primes, you can do something like this:
for ( int primeCount = 0, currentPrime = 2; primeCount < numberOfPrimes; ++currentPrime )
if ( IsPrime(currentPrime) )
{
// do whatever you want with currentPrime, like print it
++primeCount;
}
Or use the Sieve of Eratosthenes, which is a much faster method.
To figure out if a number x is prime or not, try all of its factors between 2 and Sqrt(x). Why only Sqrt(x)? Because if a*b = x, then x / b = a and x / a = b, So you would check everything twice, and also check things you shouldn't if you went up to x / 2 or even x.
So something like this if you want to use the IsPrime(x) function:
// i <= Sqrt(x) <=> i * i <= x
for ( int i = 2; i * i <= x; ++i )
if ( x % i == 0 )
return false;
return true;
But I suggest you use the sieve of Eratosthenes, as it's much faster. You can also optimize things so you don't check even numbers, since an even number is never prime, except for 2 (both in the sieve and the naive method). Treat x = 2 as an edge case and then start checking every other number (3, 5, 7, 9, 11 etc.)
What you are looking for is called "Sieve of Eratosthenes." As I'm not into doing people's homework, this is the only clue I'm going to give you. The algorithm is easily found on the internet.
The next prime number (x) - is the number which cant be devided by all primes s, that s<=sqrt(x).
So you can use function like
public bool CheckAndAddPrime(int number,List<int> primes)
{
var sqrt = Math.Sqrt(number);
foreach(var prime in primes)
{
if(prime>sqrt) break;
if(number % prime == 0) return false;
}
primes.Add(number);
return true;
}
And than you can get primes like
var primes = new List<int>();
Enumerable.Range(2,int.MaxValue).Where(x => x.CheckAndAddPrime(x,primes)).Take(YouCountOfPrimes);
var primes = Enumerable.Range(1, numberOfPrimes )
.Where(x => x != 1 &&
!Enumerable.Range2, (int)Math.Sqrt(x)).Any(y => x != y && x % y == 0));
copied from codethinked.com
static void Main(string[] args)
{
foreach (int no in get_first_k_primes(10))
{
Console.Write(" "+no.ToString() );
}
}
public static List<int> get_first_k_primes(int k)
{
var primes = new List<int>();
primes.Add(2);
int i = 3;
while(primes.Count < k)
{
if(is_prime(i))
primes.Add(i);
i += 2;
}
return primes;
}
public static bool is_prime(int n)
{
if (n % 2 == 0 && n != 2) return false;
int m = (int)Math.Ceiling(Math.Sqrt(n));
for (int i = 3; i < m; i += 2)
{
if (n % i == 0) return false;
}
return true;
}
1. Rename your variables.
Firstly, if this is homework you will get bad marks (if your teacher is worth his salt) because you have meaningless variable names (yes, even numberOfPrimes is wrong and should be named requiredNumberOfPrimes. When I see this variable I am asking myself 'Is this how many he wants, or how many he has found?').
Secondly, it will help you understand where you are going wrong. Variables should be logically named according to what they represent. If you can't explain what your variables represent (e.g. a & b) then you probably can't explain what you are doing with them.
2. Look at your loops.
for (int x = 0; x < numberOfPrimes; x++)
The structure of a for loop is (initialise; 'should I continue?'; 'each loop do this'). Therefore in your loop
You are continuing until x is equal to or great than numberOfPrimes*.
Each time you go through the loop you are adding 1 to x.
Are you sure this is what you want to do? x appears to represent the number of primes you have found. So why not increment it when you find a prime, rather than when you start a loop?
for (int a = 2; a <= x ; ++a)
for (int b = 2; b < a; ++b)
You are looking at each integer between 2 and x, inclusive. And for each of those integers a, you are looking at every integer between a and 2 inclusive. What are you going to do with these integers?
Every time you loop through your top-level loop (the x loop), you are going to start your a loop from scratch, and every time you loop through your a loop you will start your b loop from scratch.
So if x is 10, you run through a once (a=2), then you run through a again (a=2, a=3), then you run through a again (a=2, a=3, a=4), then...
3. Collect your results rather than writing them to Console.
var primes = new List<int>();
It's so easy. When you find a prime, primes.Add(a);. Then you know how many primes you have found (primes.Count), you can use the list of primes to efficiently determine the next prime, and you can use the list later on if required.
Once you do get ithe loops sorted out, you only have to check for b < sqrt(a), any higher and you would have found the other factor first.

Project Euler Question 3 Help

I'm trying to work through Project Euler and I'm hitting a barrier on problem 03. I have an algorithm that works for smaller numbers, but problem 3 uses a very, very large number.
Problem 03:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143?
Here is my solution in C# and it's been running for I think close to an hour. I'm not looking for an answer because I do actually want to solve this myself. Mainly just looking for some help.
static void Main(string[] args) {
const long n = 600851475143;
//const long n = 13195;
long count, half, largestPrime = 0;
bool IsAPrime;
half = n / 2;
for (long i = half; i > 1 && largestPrime == 0; i--) {
if (n % i == 0) { // these are factors of n
count = 1;
IsAPrime = true;
while (++count < i && IsAPrime) {
if (i % count == 0) { // does a factor of n have a factor? (not prime)
IsAPrime = false;
}
}
if (IsAPrime) {
largestPrime = i;
}
}
}
Console.WriteLine("The largest prime factor is " + largestPrime.ToString() + ".");
Console.ReadLine();
}
For starters, instead of beginning your search at n / 2, start it at the square root of n. You'll get half of the factors, the other half being their complement.
eg:
n = 27
start at floor(sqrt(27)) = 5
is 5 a factor? no
is 4 a factor? no
is 3 a factor? yes. 27 / 3 = 9. 9 is also a factor.
is 2 a factor? no.
factors are 3 and 9.
Actually, for this case you don't need to check for primality, just remove the factors you find. Start with n == 2 and scan upwards. When evil-big-number % n == 0, divide evil-big-number by n and continue with smaller-evil-number. Stop when n >= sqrt(big-evil-number).
Should not take more than a few seconds on any modern machine.
Although the question asks for the largest prime factor, it doesn't necessarily mean you have to find that one first...
long n = 600851475143L; //not even, so 2 wont be a factor
int factor = 3;
while( n > 1)
{
if(n % factor == 0)
{
n/=factor;
}else
factor += 2; //skip even numbrs
}
print factor;
This should be quick enough...Notice, there's no need to check for prime...
You need to reduce the amount of checking you are doing ... think about what numbers you need to test.
For a better approach read up on the Sieve of Erathosthenes ... it should get you pointed in the right direction.
As for the reason to accepted nicf's answer:
It is OK for the problem at Euler, but does not make this an efficient solution in the general case. Why would you try even numbers for factors?
If n is even, shift left (divide by
2) until it is not anymore. If it is
one then, 2 is the largest prime
factor.
If n is not even, you do not have to
test even numbers.
It is true that you can stop at
sqrt(n).
You only have to test primes for
factors. It might be faster to test
whether k divides n and then test it
for primality though.
You can optimize the upper limit on
the fly when you find a factor.
This would lead to some code like this:
n = abs(number);
result = 1;
if (n mod 2 = 0) {
result = 2;
while (n mod 2 = 0) n /= 2;
}
for(i=3; i<sqrt(n); i+=2) {
if (n mod i = 0) {
result = i;
while (n mod i = 0) n /= i;
}
}
return max(n,result)
There are some modulo tests that are superflous, as n can never be divided by 6 if all factors 2 and 3 have been removed. You could only allow primes for i.
Just as an example lets look at the result for 21:
21 is not even, so we go into the for loop with upper limit sqrt(21) (~4.6).
We can then divide 21 by 3, therefore result = 3 and n = 21/3 = 7. We now only have to test up to sqrt(7). which is smaller then 3, so we are done with the for loop. We return the max of n and result, which is n = 7.
The way I did it was to search for primes (p), starting at 2 using the Sieve of Eratosthenes. This algorithm can find all the primes under 10 million in <2s on a decently fast machine.
For every prime you find, test divide it into the number you are testing against untill you can't do integer division anymore. (ie. check n % p == 0 and if true, then divide.)
Once n = 1, you're done. The last value of n that successfully divided is your answer. On a sidenote, you've also found all the prime factors of n on the way.
PS: As been noted before, you only need to search for primes between 2 <= n <= sqrt(p). This makes the Sieve of Eratosthenes a very fast and easy to implement algorithm for our purposes.
Once you find the answer, enter the following in your browser ;)
http://www.wolframalpha.com/input/?i=FactorInteger(600851475143)
Wofram Alpha is your friend
Using a recursive algorithm in Java runs less than a second ... think your algorithm through a bit as it includes some "brute-forcing" that can be eliminated. Also look at how your solution space can be reduced by intermediate calculations.
Easy peasy in C++:
#include <iostream>
using namespace std;
int main()
{
unsigned long long int largefactor = 600851475143;
for(int i = 2;;)
{
if (largefactor <= i)
break;
if (largefactor % i == 0)
{
largefactor = largefactor / i;
}
else
i++;
}
cout << largefactor << endl;
cin.get();
return 0;
}
This solution on C++ took 3.7 ms on my Intel Quad Core i5 iMac (3.1 GHz)
#include <iostream>
#include <cmath>
#include <ctime>
using std::sqrt; using std::cin;
using std::cout; using std::endl;
long lpf(long n)
{
long start = (sqrt(n) + 2 % 2);
if(start % 2 == 0) start++;
for(long i = start; i != 2; i -= 2)
{
if(n % i == 0) //then i is a factor of n
{
long j = 2L;
do {
++j;
}
while(i % j != 0 && j <= i);
if(j == i) //then i is a prime number
return i;
}
}
}
int main()
{
long n, ans;
cout << "Please enter your number: ";
cin >> n; //600851475143L
time_t start, end;
time(&start);
int i;
for(i = 0; i != 3000; ++i)
ans = lpf(n);
time(&end);
cout << "The largest prime factor of your number is: " << ans << endl;
cout << "Running time: " << 1000*difftime(end, start)/i << " ms." << endl;
return 0;
}
All Project Euler's problems should take less then a minute; even an unoptimized recursive implementation in Python takes less then a second [0.09 secs (cpu 4.3GHz)].
from math import sqrt
def largest_primefactor(number):
for divisor in range(2, int(sqrt(number) + 1.5)): # divisor <= sqrt(n)
q, r = divmod(number, divisor)
if r == 0:
#assert(isprime(divisor))
# recursion depth == number of prime factors,
# e.g. 4 has two prime factors: {2,2}
return largest_primefactor(q)
return number # number is a prime itself
you might want to see this:
Is there a simple algorithm that can determine if X is prime, and not confuse a mere mortal programmer?
and I like lill mud's solution:
require "mathn.rb"
puts 600851475143.prime_division.last.first
I checked it here
Try using the Miller-Rabin Primality Test to test for a number being prime. That should speed things up considerably.
Another approach is to get all primes up to n/2 first and then to check if the modulus is 0.
An algorithm I use to get all the primes up to n can be found here.
Maybe it is considered cheating, but one possibility in haskell is to write (for the record I wrote the lines myself and haven't checked eulerproject threads);
import Data.Numbers.Primes
last (primeFactors 600851475143)

Categories

Resources