Jump to page: 1 2
Thread overview
Beyin Farkı (Brainfuck) Yorumlayıcısında Stack Sorunu
Jul 02, 2023
Salih Dincer
Jul 02, 2023
Salih Dincer
Jul 04, 2023
Salih Dincer
Jul 08, 2023
Salih Dincer
Jul 08, 2023
Ali Çehreli
Jul 09, 2023
Salih Dincer
Jul 10, 2023
Ali Çehreli
Jul 10, 2023
Cos00kun
Jul 10, 2023
Cos00kun
Jul 10, 2023
Salih Dincer
Jul 10, 2023
Cos00kun
Jul 10, 2023
Salih Dincer
Jul 10, 2023
Ali Çehreli
July 02, 2023

Merhaba,

Bu bayram verimli geçti ama bir noktada takıldım! Türkiye içinde gezerken, bilişim açısından programlamanın tarihinde de bir yolculuk yaptım...

Çoğunluk bilir, el-Hârizmî ne kadar önemliyse Alan Turing'de öyledir. Beraberinde Turing Machine ve Urban Müller'in uyguladığı Brainfuck Interpreter basittir. Bunlar ezoterik diller arasında yer alıyor ve konumuz olan kod hakkında şurada çok bilgi mevcut:

https://esolangs.org/wiki/Brainfuck_algorithms

Hoş, Thue gibi daha güzel diller ve kendinizin yapıp geliştirebileceği çok basit yorumlayıcılar mutlaka mevcuttur. Ancak ismiyle de aykırı olan (ben Beyin Farkı diyorum) BF, pekala 10 dakikada her dilde oturup yazılabilir. Hiç D dilinde yapıldı mı bilmiyorum, benim eksik çalışan (sadece ilk 4 sayının karesini doğru hesaplıyor!) ve orijinal sürüme bir komut (:) ekleyerek yaptığım şöyle:

(aslında 100 satır bile değil!)

void main()
{
  size_t ptr, i, n;            // n = gereksiz döngü sayacı
  ushort[25] mem;              // 25 eleman 100'üm karesine yeter
  auto s = CODE.dup;

  while(i < s.length)
  {
    size_t b = 1;
    switch(s[i])
    {
      case '+' : ++mem[ptr]; break;
      case '-' : --mem[ptr]; break;
      case '>' : ++ptr;      break;
      case '<' : --ptr;      break;
      case '[' :// <-YILDIZ EKLE VE GEÇİŞ YAP
        ++n;
        stack.push = i;/*/
        if(!mem[ptr])
        {
          while(b)
          {
            switch(s[++i])
            {
              case ']': --b; break;
              case '[': ++b; break;
              default : ++n; break;
            }
          }
        }//*/
        break;

      case ']' :// <-YILDIZ EKLE VE GEÇİŞ YAP
        if(mem[ptr]) i = stack.front;
        else stack.popFront;/*/
        if(mem[ptr])
        {
          while(b)
          {
            switch(s[--i])
            {
              case ']': ++b; break;
              case '[': --b; break;
              default : ++n; break;
            }
          }
        }//*/
        break;
      case ':' : writefln("->%s: %s", mem[ptr], mem); break;
      case '.' :
        const chr = cast(char) mem[ptr];
        chr.writef!"%s"; /*
        if(chr > ' ') {
          chr.write;
          mem.writefln!":->%s";
        }//*/
        break;

      case ',' :
        auto chr = cast(ubyte) stdin.readln[0];
        mem[ptr] = chr;
        break;
      default:
    }
    ++i;
  }
  n.writefln!"n = %s"; // gereksiz döngüler
  mem[$-5..$].writeln; // belleğin son 5 hücresi
}

import std.stdio;

StackLIFO!size_t stack;
struct StackLIFO(T)
{
  T[] data;

  bool empty() {
    return data.length == 0;
  }

  T back() {
    return data.length ? data[0] : T.init;
  }

  void push(T data) {
    this.data ~= data;
  }

  T front() {
    return data[$ - 1];
  }

  void popFront() {
    data.length--;
  }
}

// kodun ilk satırının sonuna (...+<+) artı işareti yerine
// eğer virgül koyarsanız ASCII değerine kadar hesaplatılabilir,
// misal ünlem(!) işareti 33'dür, en son 1024'ü hesaplar...
enum CODE = ` 30'a kadar karelerini yazar
++[>+++<-]>[<+++++>-]+<+:  ; burada 31 var
[>
  [>+>+<<-]++>>
  [<<+>>-]>>>
  [-]++>
  [-]+>>>+
  [
    [-]++++++>>>
  ]<<<
  [
    [<++++++++<++>>-]+<.< ; ekrana yaz
    [>----<-]<            ; enter \n
  ]<<
  [>>>>>
    [>>>
      [-]+++++++++<
      [>-<-]+++++++++>
      [-
        [<->-]+
        [<<<]
      ]<
      [>+<-]>
    ]<<-
  ]<<-
]`;

Lütfen değerlendirme yapmadan önce şu açıklamamı okuyun:

Kodun orijinalinden çok uzaklaşmadım. Çünkü kodda olması gerektiği gibi b değişkeni ile bracket (köşeli parantezleri) sayıyoruz. Tamam, ama bunu yapabilmek için ']' karakterinden geriye doğru gereksiz döngü ve koşullar işletiliyor. Bunu kanıtlamak için n değişkenini kullandım ve 1050'nin karesi için 208 milyon gereksiz döngü sayabildim:

>

1102500, n = 207162628

Çözüm olarak basit bir LIFO Stack oluşturdum ve döngü başladığı noktayı i değişkeni ile öğrendim. Sonuçta atlama yapılması gerekiyorsa geri yükledim (if(mem[ptr]) i = stack.front;) gerekmiyorsa bunu yığından çıkardım (else stack.popFront) yani her şey mantığa uygun ama şu sonuç elde ediliyor:

>

[0, 1, 4, 9, @, I, T, a, p ...]

Anlaşılacağı üzere iç içe döngülerde bir şey yolunca gitmiyor. Bazı BF programları çalışıyor ama böyle özel programda patlıyorum. Eğer kod içindeki <-YILDIZ EKLE VE GEÇİŞ YAP satırlarına /*/ olacak şekilde yıldız eklerseniz orijinal sürüme geri dönebilirsiniz. O zaman her şey gerektiği gibi çalışmakta. Belleğin anlık görüntüsü için ':' karakterini kodun (enum CODE) herhangi bir bir yerine koyabilirsiniz.

Özetle Beyin Farkı Yorumlayıcısı'nı, stack ile niye çalışmaz? Soruna neden olan fark ne :)

Dip Not: Orijinal interpreter'den uzaklaştığım bir diğer nokta 8 bitlik char yerine ushort kullanarak hesaplama derinliğini arttırmak oldu.

Sevgiler...

July 02, 2023

On Sunday, 2 July 2023 at 01:44:49 UTC, Salih Dincer wrote:

>

...Alan Turing de öyledir. Beraberinde Turing Machine...

Bunu yeni gördüm:

https://www.youtube.com/watch?v=E3keLeMwfHY

Bazen tembellik yapıp basit şeyleri kodlamaktan erinirken Mike Davey, teoriyi yazıldığı gibi pratiğe dökmüş! Öyle ki çok uzun bir şeridi kalem bitene kadar çalışabilecek Turing Makinesi'ni yapmış...

SDB@79

July 04, 2023

On Sunday, 2 July 2023 at 01:44:49 UTC, Salih Dincer wrote:

>

... kendinizin yapıp geliştirebileceği çok basit yorumlayıcılar mutlaka mevcuttur. Ancak ismiyle de aykırı olan (ben Beyin Farkı diyorum) BF, pekala 10 dakikada her dilde oturup yazılabilir.

Sorunun kaynağına henüz inemesem de bu, takılıp geliştirmemeyi gerektirmez çünkü etkin ve orijinal ilk 4 komut gerçekten yetersiz. Örneğin sıradan 2 kelime için bu kadar harf yazmak gerekiyor:

>

HelloWorld.bf
HelloWorld.bf
WikiPedia UK ~ Brainfuck

O yüzden şurada duyurduğum ve şimdilik 12 buyruk kümesine (IS : Instruction Set) sahip BF v1.04s sürümünü yayınladım. Sıkıştırılmış az satırlı örneği de aşağıda:

enum helloWorld = "++++++++++[>+++++++>++++++++++>+++><<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.";

import std.stdio;
void main() {
  size_t ptr, i;
  ushort[5] mem;
  auto s = helloWorld.dup;
  auto l = s.length;

  while(i < l) {
    size_t b = 1;
    switch(s[i]) {
      case '#' : ptr.writeln(": ", mem);
        break;
      case '&' : mem[++ptr] += mem[ptr - 1];
        break;
      case '^' : mem[ptr] <<= 1;
        break;
      case 'v' : mem[ptr] >>= 1;
        break;
      case '\n': writeln();     break;
      case '+' : ++mem[ptr];    break;
      case '-' : --mem[ptr];    break;
      case '>' : ++ptr;         break;
      case '<' : --ptr;         break;
      case '[' : stack.push(i); break;
      case ']' :
        if(mem[ptr]) i = stack.front();
        else stack.popFront();  break;
      case '.' :
        const chr = cast(char) mem[ptr];
        chr.writef!"%s";        break;
      case ',' :
        auto chr = cast(ubyte) stdin.readln[0];
        mem[ptr] = chr;         break;
      default:
    }
    ++i;
  }
}

StackLIFO!size_t stack;
struct StackLIFO(T) {
  private T[] data;  
  auto length() => data.length;
  auto empty() => data.length == 0;
  auto back() => data.length ? data[0] : T.init;
  auto push(T data) => this.data ~= data;
  auto front() => data[$ - 1];
  auto popFront() => data.length--;
}
July 08, 2023

On Tuesday, 4 July 2023 at 13:32:02 UTC, Salih Dincer wrote:

>

Sorunun kaynağına henüz inemesem de bu, takılıp geliştirmemeyi gerektirmez...

Sanırım sorunun kaynağını bulamamak bende takıntı haline geldi. Çünlü ChatGPT dahil kime sorsam cevaplayamadı ama çözmek istiyorum. Veee bugün, aşağıda paylaşacağım ve C üzerinden yaptığım bir sohbette şaşırtıcı bir şey oldu!

ChatGPT, ben yönlendirmesem de sanki benim aklımı okumuş ya da foruma yazdıklarımı veritabanına işlemiş (oysa itiraf ediyor, Bing'deki sürümün yapabildiği gibi siteleri okuyamıyor). Jump Table oluşturmayı denedi, işte 3 sürümlü sohbet:

https://chat.openai.com/share/05fc7f49-a76e-4127-b3b6-5b4302a52ed9

Üç sürümden biri benim çözümüm ama en sonunda karşılaştırmasını istedim ve sorunun yanına bile gelemedi!

Allah Allah, diyorum başka da bir şey demiyorum :)

July 08, 2023
On 7/1/23 18:44, Salih Dincer wrote:

>> 1102500, n = 207162628

Ben stack'i kullanınca şunu yazıyor:

n = 7102

stack kullanmayınca şunu:

n = 502312478

Onun dışında iki çıktı da tamamen aynı. (?)

Ali

July 09, 2023

On Saturday, 8 July 2023 at 23:37:54 UTC, Ali Çehreli wrote:

>

stack kullanmayınca şunu:

n = 502312478

Onun dışında iki çıktı da tamamen aynı. (?)

Evet, döngü mantığı stack kullanmaya müsait ama sorun şu ki çalışmıyor:

playground

Sağdaki search&skip yöntemini uygularken soldaki derleme hatası veriyor ve stack&jump yöntemini uygulmakta.

Acaba senin PC nasıl ki çalıştı, derleyici sürümü ne?

Denediğin için teşekkürler...

July 09, 2023
On 7/9/23 10:10, Salih Dincer wrote:

> Acaba senin PC nasıl ki çalıştı

Bende ikisi de aynı oluyor ama galiba ikisi de yanlış çünkü senin gösterdiğin gibi tamsayı olmadı. (Çıktıyı elimle düzelttim: Örneğin, "\201" yazan yerde aslında 4 karakter değil tek '\201' kodu var.)

->31: [31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0
1
4
9
@
I
T
a
p
\201
\224
\251
\300
\331
\364
^Q
0
Q
t
\231
\300
\351
^T
A
p
\241
\324
	
@
y
\264
n = 502312478
[0, 0, 0, 0, 0]

> derleyici sürümü ne?

dmd v2.103.0

Ali

July 10, 2023
On Monday, 10 July 2023 at 00:43:14 UTC, Ali Çehreli wrote:
> Ali

Bendeki sonuç da şöyle çıkıyor;

->31: [31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0
1
4
9
@
I
T
a
p
�
�
�
�
�
�

0
Q
t
�
�
�

A
p
�
�
	
@
y
�
n = 7102
[0, 0, 0, 0, 0]
================ READY ================

July 10, 2023
On Monday, 10 July 2023 at 05:42:38 UTC, Cos00kun wrote:
> ================ READY ================

yukarıda utf-8 ile derlendiğindeki sonuçmuş kusura bakmayın.
ansi ile sonuç;

->31: [31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0
1
4
9
@
I
T
a
p
�
�
�
�
�
�

0
Q
t
�
�
�

A
p
�
�
	
@
y
�
n = 7102
[0, 0, 0, 0, 0]

Win-x64 ,, Notepad++

July 10, 2023

Ben galiba hibrit bir çözüm buldum, bu sayede 50 milyon döngüden 145 bine verimli bir optimisazyon sağlamış oldum!

Ali hocam bir bakar mısın, bu kod sende çalıştı mı?

import std.stdio;
//import std.ascii : isWhite;/*
bool isWhite(dchar c) @safe pure nothrow @nogc {
  return c >= 0x09 && c <= 0x0D;
}//*/

enum cellTest = ">>+<[>[<-]<[->+<]>]>#"; //BFv1.4
alias Type = ushort;

void main()
{
  Type ptr, i, n, index;
  ushort[25] mem;
  Type[5] stack;

  //auto code = cellTest.dup;/*
  auto code = CODE.dup;//*/

  while(i < code.length)
  {
    switch(code[i])
    {
      case '>': ++ptr; break;
      case '<': --ptr; break;
      case '+': ++mem[ptr]; break;
      case '-': --mem[ptr]; break;

      case '#': // view first 5 cells of memory
        ptr.writeln(": ", mem[0..5]);
        break;

      case '[':
        int balance = 1;
        if(!mem[ptr])
        {
          while(balance)
          {
            switch(code[++i])
            {
              case ']': --balance; break;
              case '[': ++balance; break;
              default : ++n;// skip char.
            }
          }
        } else stack[index++] = i;
        break;

      case ']':
        if(mem[ptr]) i = stack[index - 1];
        else index--;
        break;

      case '.' :
        const chr = cast(char) mem[ptr];
        chr.writef!"%s";
        break;

      case ',' :
        auto chr = cast(ubyte) stdin.readln[0];
        mem[ptr] = chr;
        break;

      default: --n;
    }
    ++n;
    ++i;
  }
  n.writeln(" defa döngü devam etti...");
}

enum CODE = "++[>+++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]"; // BF Original Code

Dip Not: Sanırım BF camiasında özel bir hack yapıldığından bazı programlar stack'li sürümde çalılmıyordu. Stack olayını statik bir dizi ile halledip kodu kısalttım. Artık harika çalışıyor ama 2. bir switch ile yapılan ve orijinal kodda olan skip char. bölümü şart o yüzden melez bir çözüm oldu ya :)

Sevgiler, saygılar...

« First   ‹ Prev
1 2