August 23

Hayırlı cumalar,

Bundan yaklaşık 12 sene önce şurda bir önceki sürümü yayınlamıştım. Elbette o günden bugüne çok şey öğrendim; C temelliydim ve henüz higher order function - HOF kavramını dahi öğrenememiştim. Ve elbette aslında v7'yi ara sürümlerini ve belki v9-10 çok hatırlamıyorum yaptım ama yayınlamadım. Çünkü bundan daha gelişmiş algoritmalar üzerine (veya RSA) üzerine çalıştım, çalışıyorum...

Gece uyku tutmadı ve acaba yapay zeka bu uzun zaman diliminde 12 yıllık bilgi birikimini bana tek soruyla verebilir mi diye merak ettim! Sonuçta www.you.com üzerinden bana verilen 3 sorgulama hakkıyla GPT-4o'yu kıvama getirmeyi başardım. İlkin şu cevabı verdi:

import std.stdio;
import std.algorithm;
import std.range;

// Bit manipülasyonu ile asal sayıları bulan fonksiyon
auto sieveOfEratosthenes(size_t limit) {
    ubyte[] isPrime = new ubyte[(limit + 7) / 8];
    isPrime[] = 0xFF; // Tüm bitleri 1 yaparak başla
    isPrime[0] &= ~1; // 0 ve 1 asal değil

    for (size_t p = 2; p * p <= limit; ++p) {
        if (isPrime[p / 8] & (1 << (p % 8))) {
            for (size_t i = p * p; i <= limit; i += p) {
                isPrime[i / 8] &= ~(1 << (i % 8));
            }
        }
    }

    return iota(2, limit + 1).filter!(i => isPrime[i / 8] & (1 << (i % 8)));
}

// Kullanıcının girdiği sayıya karşılık gelen N'inci asal sayıyı bulan fonksiyon
size_t prime(size_t n) {
    auto primes = sieveOfEratosthenes(2_100_000_000); // 2.1 milyara kadar asal sayılar
    return primes[n - 1]; // N'inci asal sayıyı döndür
}

void main() {
    size_t userInput;
    writeln("Lütfen 1 ile 2.1 milyar arasında bir sayı girin:");
    readf(" %s", &userInput);

    // Kullanıcının girdiği sayıya karşılık gelen asal sayıyı yazdır
    userInput.prime().writeln();
}

Çok hata var, elbette çalışmıyor! Çünkü en bariz hata aralık döndüren bir işleve [n - 1] ile tıpkı bir dizi gibi erişmek. Hiç takılmadım, return sonuna .array ekleyecekti ve o da 3 soru/cevaplık konuşmamız sırasında eklemeyi lüzum görmedi, pek akıllı uygulama :)

Asıl takılacak nokta, neden çift sayılar ve boolean değerler için ~ işaretini kullanarak complementary ile kafaları karıştırmış? Üstelik 0 sayısı ile varsayılan ilklenen dizileri zorlayarak boolean matematiği için true yapmaya ve her şeyi ona göre kurgulamaya çalışması da bence ahmakca!

Neyse, en azından "kalbur, sieve, Eratosthenes" dediğimde hemen bool[] dizisi kuran Google Gemini, GPT3 vb.'leri gibi davranmamakla ilgimi çekmiş oldu. Diğer 2 hakkımda neden çalışmadığını sormak yerine adeta onu bir öğrenci gibi geliştirmeye çalıştım; eğer bunlar bir yerlerde kaydediliyorsa tabi.

Çok uzatmayayım! Az önce, onun implement edemediğinin bir benzerini bir yapı haline aşağıdaki gibi getirdim. Elbette işlev hali de güzeldi ama kullanıcıdan sürekli bir sayı girmesini isterseniz, her seferinde Eratosthenes Kalburu'nu doldurması gerekecekti. Birkaç sihirli dokunuş, hızlı/yavaş her sistemde (embedded makinelerde bile) çalışcak kod bitti.

/*
* asalTaraRef.d (v7 - 23.08.2023)
*/
struct AsalTara
{
  ubyte[] veri;
  int[] primes;

  import std.algorithm : filter;
  import std.range : array, iota;

  this(int son) {
    veri = new ubyte[](son / 16 + 1);
    veri.length.writefln!"Buffer Length = %,3s bytes";

    writeln("Please wait, filling...");

    for (int p = 3; p <= son; p += 2) if (get(p))
    for (int i = 3; i <= son / p; i += 2) set(p * i);

    writeln("Generating prime numbers...");

    primes = [2];
    primes ~= 3.iota(son + 1, 2)
               .filter!(i => get(i))
               .array;

    primes.length.writefln!"Max Length = %,3s";
  }

  auto prime(int n) { return primes[n - 1]; }

  private
  {
    ubyte mask(int n) {
      return cast(ubyte)(1 << ((n % 16) >> 1));
    }

    bool get(int n) {
      return (veri[n >> 4] & mask(n)) == 0;
    }

    void set(int n) {
      veri[n >> 4] |= mask(n);
    }
  }
}

import std.stdio;
enum limit = 49_979_777; // 3000004 (max.)

void main()
{
  auto get = AsalTara(limit);
  get.prime(1000).writeln;

  int n;
  do {
    writeln("Lütfen 1 ile 2.1 milyar arasında bir sayı girin:");
    readf(" %s", &n);

    // Girilen sayıya karşılık gelen asal sayıyı yazdır:
    if (n > 0 && n <= get.primes.length)
      get.prime(n).writeln;

  } while(n > 0);
}

Bu algoritma nispeten yavaş olduğu için de her şeyi int ile sınırladım. Elbette önceki sürümdeki 2 aralık arasındaki sayıları listelemek isterseniz, kod benzediğinden bunu uyarlayarak belleği daha etkin kullanabilirsiniz. Ancak şu haliyle, yaklaşık 3 MB. bellek kullanarak gayet hızlı bir şekilde ilk 3 milyon asalı size veriyor. Limitlerle oynamaktan çekinmeyin. İsterseniz sırayla on, yüz, bin ya da milyon şeklinde şu sekans ile doğrulayabilirsiniz de: https://oeis.org/A006988

SDB@79

August 24

On Friday, 23 August 2024 at 06:28:57 UTC, Salih Dincer wrote:

>

Bu algoritma nispeten yavaş olduğu için de her şeyi int ile sınırladım.

Ekstra bir şey, ikili veriyi işlemek için örn. 9 sn. zamana ihtiyaç varsa, aşağıdaki alternatif size bu süreyi 3 saniyeye indirmenizi olanak veriyor; daha da kısaltmak mümkün olabilir...

  //...
    writeln("Generating prime numbers...");
    auto süre = ÖLÇ(true);
    primes = [2];
    //primes ~= 3.iota(son + 1, 2).filter!(i => get(i)).array;/*
    int n = 1;
    foreach (v; veri)
    {
      for (int i; i < 8; ++i, n += 2)
      {
        if (v % 2 == 0) primes ~= n;
        v >>= 1;
      }
    }//*/
    süre.dur();
    primes.length.writefln!"Max Length = %,3s";
  }

SDB@79