Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Solution to Google Treasure Hunt 2008 - Task 4

The program below can be used to solve a particular instance of the task presented at http://treasurehunt.appspot.com (Task 4, 2008). You are given few numbers, e.g. [1111, 137, 13, 3]. Your task is to find smallest prime that is a sum of 1111 consecutive primes, sum of 137 consecutive primes and so on.

The values are placed in limits array, but you can also pass them as arguments (in descending order!) from command line:

    ./TreasureHunt4 799 415 63 31

The code allows to compare BitArray with array of booleans. BitArray? is a bit slower, but should occupy less memory. Implementation uses Atkin sieve.

Code can be compiled with debug option for additional informations.

/* Michal 'GiM' SpadliƄski             <gim913 & gmail * com >
 * 
 * Google TreasureHunt task 4 solution
 * http://treasurehunt.appspot.com/
 */
module TreasureHunt4;

//version = BitArray;

import tango.io.Stdout;
import tango.time.StopWatch;
import Integer = tango.text.convert.Integer;
version ( BitArray )
    import tango.core.BitArray;


static const int sqrt_val = 2500;
// descending order
int[] limits = [1111, 137, 13, 3];


ulong primes[];
static this()
{   
    StopWatch timer;
    timer.start;
    some_small_primes = atkin_sieve;
    foreach (k, a; some_small_primes)
        if (a)
            primes ~= k;
    auto temp = timer.stop;
    Stdout.formatln ("primes table generated in {} seconds with {} entries", temp, primes.length);
}

class PrimesSum
{
private:
        ulong _sum;
        int start;
        int limit;
public:
    this(int lim)
    {   
        limit = lim;
        for (int j=0; j<limit; ++j)
            _sum += primes[j];
    }
    
    void next()
    {   
        _sum -= primes[start];
        _sum += primes[start+limit];
        ++start;
    }
    void previous()
    {   
        --start;
        _sum -= primes[start+limit];
        _sum += primes[start];
    }

    int opCmp(PrimesSum b) { return _sum - b.sum; }
    int opEquals(PrimesSum b) { return _sum == b.sum; }

    uint sum() { return _sum; }

    char[] toString()
    {   
        char[100] tmp = void;
        return Integer.format (tmp, _sum, Integer.Style.Unsigned, Integer.Flags.None).dup;
    }
}

void main(char[][] argv)
{
    PrimesSum[] prSums;
    StopWatch timer;

    if (argv.length > 1)
    {   
        limits = [];
        foreach (char[] arg; argv[1..$])
            limits ~= Integer.toInt(arg);
        Stdout(limits).newline;
    }

    timer.start;

    prSums.length = limits.length;
    foreach (a, ref b; prSums)
        b = new PrimesSum(limits[a]);

OUTER_LOOP:
    for(;;)
    {   
        // Sum must be a prime
        try {
            while (1)
            {   
                if (some_small_primes[prSums[0].sum])
                    break;
                else
                    prSums[0].next;
            }
        } catch (Exception e) {
            assert (0, "Increase the value of sqrt_val in the source file");
        }
        debug Stdout.formatln ("0: {} {}", prSums[0].sum, prSums[0].start);

        // check if all the other, smaller sums, sum to the same number
        for (int idx=1; idx<prSums.length; ++idx)
        {   
            while (prSums[idx] < prSums[0])
                prSums[idx].next;
            debug Stdout.formatln ("{}: {} {}", idx, prSums[idx].sum, prSums[idx].start);
            if (prSums[idx] != prSums[0])
            {   
                debug Stdout ("differ2").newline;
                prSums[0].next;
                for (int i=1; i<=idx; ++i)
                    while (prSums[i] > prSums[0])
                        prSums[i].previous;
                continue OUTER_LOOP;
            }
        }
        // we got you
        break;
    }
    auto temp = timer.stop;
    Stdout ("The Answer to the Great Question ...")
        .formatln ("Of Life, the Universe and Everything: {}", prSums[0]);
    Stdout  ("input data: ") (limits).newline;
    Stdout.formatln ("Finding answer took {} seconds", temp);
}

T atkin(T, int sqrt_limit)()
{
    const long limit = sqrt_limit*sqrt_limit;
    T firstSet;
    firstSet.length = limit;
    
    firstSet[2] = 1;
    firstSet[3] = 1;
            
    for (auto x = 1; x<sqrt_limit; ++x)
    {
        for (auto y=1; y<sqrt_limit; ++y)
        {
            auto n = 4 * x*x + y*y;
            if (n < limit && ((n % 12) == 1 || (n % 12) == 5))
                firstSet[n] = cast(bool)1^firstSet[n];
            n = 3 * x*x + y*y;
            if (n < limit && ((n % 12) == 7))
                firstSet[n] = cast(bool)1^firstSet[n];
            n = 3 * x*x - y*y;
            if (n < limit && x > y && ((n % 12) == 11))
                firstSet[n] = cast(bool)1^firstSet[n];
        }
    }   
    for (int n=5; n<sqrt_limit; ++n)
    {   
        if (firstSet[n])
            for (int k=1, j=n*n; j*k<limit; ++k)
                firstSet[k*j] = 0;
    }   
    return firstSet;
}       
    
version ( BitArray )
{   
    static const BitArray some_small_primes;
    alias atkin!(BitArray, sqrt_val) atkin_sieve;
} else  {
    static const bool[] some_small_primes;
    alias atkin!(bool[], sqrt_val) atkin_sieve;
}   

Here is sample run of a program on Core Duo 1.7 with sqrt_val set to 2630, this also show how fast D is:

primes table generated in 1.07 seconds with 471342 entries
[ 799, 415, 63, 31 ]
The Answer to the Great Question ...Of Life, the Universe and Everything: 6814289
input data: [ 799, 415, 63, 31 ]
Finding answer took 0.00 seconds