April 25

Merhaba,

D'de (sanırım) size asal sayı dizisi veren hazır bir algoritma yok. Geçenlerde hız testleri yapmak için (belki siz kriptolojide kullanmak istersiniz) hazır ve basit algoritma aradım bulamadım. Aklıma ilk şurası geldi:

https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Extensible_Version

Ama ya çok karışıklar ya da yeterince iyi değiller, hatta eskiler! İhtiyacım olan şöyle bir şey:

bool isPrime(T)(T n) pure
{
  if(n <= 1) return false;
  if(n <= 3) return true;
  if(n % 2 == 0 || n % 3 == 0) return false;

  for(auto i = size_t(5); i * i <= n; i += size_t(6))
  {
    if(n % i == 0 || n % (i + 2) == 0)
    {
      return false;
    }
  }
  return true;
}

İsmi ve yaptığı çok güzel. Her yerde işinize yarar ama yetmez! Çünkü küçük bir liste için bakınız tonlarca şeye ihtiyacınız var:

alias type = uint;
enum limit = 25;
import std;

void main()
{
  iota(type.max).filter!(a => a.isPrime)
                .take(limit)
                .writeln;
} /* ÇIKTISI:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
//*/

Tamam biraz abartmış olabilirim! Yine de sayalım: iota, filter, take ve import ile modülleri eklemek gerek. Yani ilk 25 asal sayıyı yazmak için yorucu sanki, peki şu yardımcı araç ile güzel bir ikili oluşturabilirler mi?

auto sieve(T)(T limit, T first = 1)
in(limit > 0 && first > 0, "SIFIR OLMAMALI") {
  T[] list;
  do if(first.isPrime) {
    list ~= first;
    if(--limit == 0) break;
  } while(++first > 0);
  return list;
}

Hem de tadından yenmez çünkü 2 parametre alıyor. Diyelim ki 100'den sonraki asal sayılara ihtiyacınız var, işte bu kadar basit:

  limit.sieve(100).writeln;

  // [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229]

Seçim sizin! Elbette aynı çıktıyı standart kütüphanedeki bazı işlevlerle de yapabilirsiniz. Örneğin ilk verdiğim senaryoyu 100.iota(type.max) şeklinde değiştirirseniz ikinci ile aynı olacaktır.

Son olarak BONUS:

RosettaCode'da yer alan 'Extensible Version' çok karışıktı, biraz düzenledim. Benzer şeyleri yapma yeteneğine opCall() ve ekstra skip değişkeni sayesinde bu yapı da sahip:

alias Sieve = ExpandingFactors;
struct ExpandingFactors(T)
{
  T[] list;

  auto opCall(in T n)
  {
    if(list.empty) list ~= 2;
    while(n >= list.length) next();
    return list[n];
  }

  void next()
  {
    auto last = list[$ - 1] + 1;
    auto buff = new bool[last];
    // Disabling candidates
    T n;
    foreach(p; list)
    {
      n = last / p * p;
      if (n < last) n += p;
      for(n -=last; n < buff.length; n += p)
      {
        buff[n] = true;
      }
    }
    // Expanding factors
    n = 0;
    while (n < buff.length)
    {
      if (!buff[n]) list ~= last + n;
      ++n;
    }
  }
}

alias type = uint;
enum limit = 25;
import std;

void main()
{
  Sieve!type primes;

  auto skip = 50; // ilk 50 asalı atla
  skip.iota(limit + skip)
      .map!primes
      .writeln;
} /* ÇIKTISI:
[233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379]
//*/

SDB@79