Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help speed up this algorithm? Sieve of Eratosthenes

I've written an algorithm that I believe to be correct for computing prime numbers up to n with the Sieve of Eratosthenes. Unfortunately, this program hangs on really large values of n (try 10 million). Here is what I've written...

Protected Function Eratosthenes(ByVal n As Integer) As String
    Dim maxValue As Integer = Math.Sqrt(n)
    Dim values As Generic.List(Of Integer) = New Generic.List(Of Integer)
    Dim i As Integer
    ''//create list.
    For i = 2 To n
        values.Add(i)
    Next

    For i = 2 To maxValue
        If values.Contains(i) Then
            Dim k As Integer
            For k = i + 1 To n
                If values.Contains(k) Then
                    If (k Mod i) = 0 Then
                        values.Remove(k)
                    End If
                End If
            Next
        End If
    Next

    Dim result As String = ""
    For i = 0 To values.Count - 1
        result = result & " " & values(i)
    Next

    Return result
End Function

How might I speed this algorithm up? Where are my bottlenecks?

like image 521
Chris Avatar asked Dec 02 '22 07:12

Chris


2 Answers

Removing elements from a large list is slow.

Why not create an array of Booleans values instead and set a value to "True" when you know that it's non-prime?

When you've found a new prime, you don't need to go through all higher values, just multiple of that one, setting the array element to True.

You can keep a separate list for primes you've found so far, if you want to return them.

Here's a C# implementation which just prints them out as it goes. (In C# if I wanted to return the values I'd return IEnumerable<T> and use an iterator block.)

using System;

public class ShowPrimes
{
    static void Main(string[] args)
    {
        ShowPrimes(10000000);
    }

    static void ShowPrimes(int max)
    {        
        bool[] composite = new bool[max+1];
        int maxFactor = (int) Math.Sqrt(max);

        for (int i=2; i <= maxFactor; i++)
        {
            if (composite[i])
            {
                continue;
            }
            Console.WriteLine("Found {0}", i);
            // This is probably as quick as only
            // multiplying by primes.
            for (int multiples = i * i;
                 multiples <= max;
                 multiples += i)
            {
                composite[multiples] = true;
            }
        }
        // Anything left is a prime, but not
        // worth sieving
        for (int i = maxFactor + 1; i <= max; i++)
        {
            if (composite[i])
            {
                continue;
            }
            Console.WriteLine("Found {0}", i);
        }
    }
}
like image 150
Jon Skeet Avatar answered Dec 04 '22 07:12

Jon Skeet


I am not a VB guy, but I think:

values.Remove(k)

is a waste of time, just set the place to 0, then extract the prime numbers to another list or sort the same list and remove all zeros at once.

like image 36
Khaled Alshaya Avatar answered Dec 04 '22 05:12

Khaled Alshaya