ProjectEuler problem 35

Era Scarecrow rtcvb32 at yahoo.com
Wed May 16 03:38:01 PDT 2012


On Wednesday, 16 May 2012 at 09:46:06 UTC, Dmitry Olshansky wrote:
> On 16.05.2012 13:26, Tiberiu Gal wrote:

>> foreach(i; 2 .. Max) {
>> //writefln("is %s prime ? %s ", i, i.isPrime);
>> if( i.isPrime && i.isCircularPrime) {
>> cnt++;

  Curiously i've just posted a sample (as part of another topic) 
that progressively gives your larger primes. I haven't speed 
tested it, but it always spits out primes.

http://forum.dlang.org/thread/jovicg$jta$1@digitalmars.com

So your code might look like...

primes_walk pw;
pw.cap = 1_000_000;

  foreach(i; pw) {
  if( i.isCircularPrime) { //i is always prime


>> bool isCircularPrime( int n) {
>>
>> auto c = to!string(n);
>> for(int i ; i < c.length; i++){
>> c = c[1 .. $] ~ c[0];
>
> Don't ever do that. I mean allocating memory in tight cycle.
> Instead use circular buffer.  (just use the same array and wrap 
> indexes)

  Hmm... I'd say this is totally written wrong... Rewriting it to 
a more optimized one I got 15ms as a total running time for 
1_000_000 numbers. answer I got was 3181... remember I'm not 
optimizing it or anything.

  If this is a gem to show the power & speed of D, by all means 
use it. But I want credit for my prime_walk...

real    0m0.257s
user    0m0.015s
sys     0m0.015s


-- rewrite with prime_walk
module te35;

import std.stdio;

//prime_walk by Era Scarecrow.
//range of primes, nearly O(1) for return.
struct prime_walk {
   int map[int];
   int position = 2;
   int cap = int.max;

   int front() {
     return position;
   }

   void popFront() {
     //where the real work is done.

     if ((position & 1) == 0) {
       position++;
     } else if (position>= cap) {
       throw new Exception("Out of bounds!");
     } else {
       int div = position;
       int p2 = position * 3;

       //current spot IS a prime. So...
       if (p2 < cap)
         map[p2] = div;

       position += 2;

       //identify marked spot, if so we loop again.
       while (position in map) {
         div = map[position];
         map.remove(position);
         p2 = position;
         do
           p2 += div * 2;
         while (p2 in map);

         position += 2;
         if (p2 <= cap)  //skip out, no need to save larger than 
needed values.
           map[p2] = div;
       }
     }
   }

   bool empty() {
     return position >= cap;
   }
}


const Max = 1_000_000;

bool[Max] primes;

void main() {
   assert(bool.init == false);  //just a speedup if true. removes 
15ms
   int cnt;
   prime_walk pw;
   pw.cap = Max; //no primes larger than 1Mil

   foreach(i; pw) { //i is ALWAYS prime.
     primes[i] = true;  //removes need for isprime totally if we 
are never going above the foreach's i
     if(i.isCircularPrime) {
       cnt++;
//      writefln("\t\tis %s, circular prime ", i); //already 
confirmed
     }
   }

   writeln(cnt);

}

//bool isPrime(int); //removed, not needed in this case

//since it's always lower...
//removes need for string, and only uses 1 division per level
immutable int[] levels = [
//1_000_000_000, 100_000_000, 10_000_000,  //completeness sake.
1_000_000, 100_000, 10_000, 1_000, 100, 10];

bool isCircularPrime(int n) {

   foreach(l; levels) {
     if (l > n)
       continue;

     if (primes[n] == false)
       return false;

     n %= l; //remainder of 10, sorta...
   }
   return true;
}


More information about the Digitalmars-d-learn mailing list