ウィキペディアよりも速く数十億の単純な数字をふるいにかける

図のソース

エラトステネスのふるい(RE)は、コンピューターが発明されるずっと前に登場した最も古いアルゴリズムの1つであることはよく知られています。 したがって、このアルゴリズムは何世紀にもわたって上下に研究されてきており、何も追加できないと考えるかもしれません。 ウィキペディアを見ると、簡単にdrれることができる信頼できるソースへのリンクがたくさんあります。 したがって、先日、Wikipediaで最適と表示されているオプションが大幅に最適化できることを偶然発見したとき、私は驚きました。

そんな感じでした。 関数型プログラミング(FP)に関する記事の議論で、彼は質問をしました 。このパラダイムでREを書く方法です。 FPの知識が乏しい以上、答えを判断する勇気はありませんが、議論の他の参加者はすぐに提案された解決策のいくつかを拒否し、理論的な複雑さの代わりに

On log logn(1)

提案された実装には計算の複雑さがあります

On2/ logn(2)

そして、そのような複雑さのために、たとえば1000万の数字がふるいにかけられるとき、あなたは待つことができません。 私は興味を持ち、ウィキペディアに従って、通常の手続き型プログラミングを使用して最適なバージョンを実装しようとしました。 Delphi-7では、次のコードを取得しました。

リスト1
program EratosthenesSieve;
// Sieve of Eratosthenes
{$APPTYPE CONSOLE}

uses
  SysUtils, DateUtils,Math;
const
 version ='1.0.1d1';
 N = 1000000000; // number of primes
var
 sieve : array [2..N] of boolean; // false if prime
 t0, t1,dt : TDateTime;
 O,C : Extended;

procedure init;
  var
   i : integer;
  begin
   for i:=2 to n do
    sieve [i] := false;
  end; //init

procedure calc (start : integer);
  var
   prime, i : integer;
   breakLoop, exitProc : Boolean;
  begin
   prime := start;
   exitProc := false;
   repeat
// find next prime
      prime := prime+1;
      while (prime<N) and sieve[prime] do
       inc (prime);
      i:= sqr(prime);
// delete
      if i<= N then
        begin
          breakLoop := false;
          repeat
            if i<= N then
             begin
              sieve [i] := true;
              inc (i,prime);
             end
            else  // if i<= N
             breakLoop := true;
          until breakLoop;
        end  
      else // if prime+prime<= N
       exitProc := true;
   until exitProc;
  end; //calc

procedure print;
  var
    i :integer;
    found : integer;

  begin
    found := 0;
    for i:=2 to N do
     if not sieve [i] then
      begin
//       write (i,', ');
        inc(found);
      end;
    writeln;
    writeln ('Found ',found,' primes.');
  end; //

begin // program body
  writeln ('Sieve of Eratosthenes version ', version);
  writeln('N= ',N);

  init;
  t0 := now;
  writeln('Program started ',DateTimeToStr(t0));
  t0 := now;
  calc (1);
  t1 := now;
  writeln('Program finished ',DateTimeToStr(t1));
  dt := SecondSpan(t1,t0);
  writeln ('Time is ',FloatToStr(dt),' sec.');

  O := N* ln(ln(N));
  C := dt/O;
  writeln ('O(N ln ln N)= ',O,' C=',C);

  O := sqr(N)/ln(N);
  C := dt/O;
  writeln ('O(N*N/ln N)= ',O,' C=',C);

  print;
  
  writeln ('Press Enter to stop...');
  readln;
end.


sieve — , false, (not) . 3 : — init, ( ) — calc — print, . print: N=1000 .

calc : i

i2,i2+i,i2+2i,



17.6 . (CPU Intel Core i7 3.4 ).
, .

1. 1) +=; 2) +=; 3) += .



1) (2n+1)+(2m+1)=2n+2m+22. .
2)(2n+1)+(2m)=2n+2m+1 2 . .
3)(2n)+(2m)=2n+2m 2. .

2. .
. (2n+1)2=4n2+4n+12 . .

. , 2, .

:

i2,i2+2i,i2+4i,(3)

. init.

2
program EratosthenesSieve;
// Sieve of Eratosthenes
{$APPTYPE CONSOLE}

uses
  SysUtils, DateUtils,Math;
const
 version ='1.0.1d1';
 N = 1000000000; // number of primes
var
 sieve : array [2..N] of boolean; // false if prime
 t0, t1,dt : TDateTime;
 O,C : Extended;

procedure init;
  var
   i : integer;
  begin
   for i:=2 to n do
    sieve [i] := not odd(i); 
  end; //init

procedure calc (start : integer);
  var
   prime,prime2, i : integer;
   breakLoop, exitProc : Boolean;
  begin
   prime := start;
   exitProc := false;
   repeat
// find next prime
      prime := prime+1;
      while (prime<N) and sieve[prime] do
       inc (prime);
//      i:= prime*prime;
      i:= sqr(prime);
      prime2 := prime+prime;   
// delete
      if i<= N then
        begin
          breakLoop := false;
          repeat
            if i<= N then
             begin
              sieve [i] := true;
              inc (i,prime2);
             end
            else  // if i<= N
             breakLoop := true;
          until breakLoop;
        end  
      else // if prime+prime<= N
       exitProc := true;
   until exitProc;
   sieve [2] := false;
  end; //calc

procedure print;
  var
    i :integer;
    found : integer;

  begin
    found := 0;
    for i:=2 to N do
     if not sieve [i] then
      begin
//      write (i,', ');
        inc(found);
      end;
    writeln;
    writeln ('Found ',found,' primes.');
  end; //

begin // program body
  writeln ('Sieve of Eratosthenes version ', version);
  writeln('N= ',N);

  init;
  t0 := now;
  writeln('Program started ',DateTimeToStr(t0));
  t0 := now;
  calc (2);
  t1 := now;
  writeln('Program finished ',DateTimeToStr(t1));
  dt := SecondSpan(t1,t0);
  writeln ('Time is ',FloatToStr(dt),' sec.');

  O := N* ln(ln(N));
  C := dt/O;
  writeln ('O(N ln ln N)= ',O,' C=',C);

  O := sqr(N)/ln(N);
  C := dt/O;
  writeln ('O(N*N/ln N)= ',O,' C=',C);

  print;
  
  writeln ('Press Enter to stop...');
  readln;
end.


9.9 . – .

,

dt=CO,



dt– ;
C– ;
O– .

C(1) (2). N=106dt. N.

N(1)(2)
1071.691092.74109
1085.141091.47108
1095.801091.29107

, (1) . . , (3) , . , .

PS « » .

Source: https://habr.com/ru/post/J450604/


All Articles