atarionline.pl Języki programowania - testy - Forum Atarum

    Jeśli chcesz wziąć udział w dyskusjach na forum - zaloguj się. Jeżeli nie masz loginu - poproś o członkostwo.

    • :
    • :

    Vanilla 1.1.4 jest produktem Lussumo. Więcej informacji: Dokumentacja, Forum.

      • 1: CommentAuthorzbyti
      • CommentTime28 Feb 2020 11:02 zmieniony
       
      Chciałbym przeprowadzić bardziej miarodajne testy wydajności niż FAKE SIEVE lub REAL SIEVE z tego wątku ->link<-

      Pomysł na początek jest taki, że uzupełnię test YoshPlus o brakujące języki.

      Przeprowadzę też test obliczania silni, bo wygląda na to, że procedury odpowiedzialne za mnożenie nie są jednolite i różnią się wydajnością w różnych językach.

      Do pełni szczęście brakuje mi PAUZY by synchronizować się z ramką, jak to jest w Mad Pascalu.

      system.pas
      procedure Pause; assembler; overload;
      (*
      @description:
      Delay program execution (1/50 second).
      *)
      asm
      { lda:cmp:req :rtclok+2
      };
      end;

      Czy ktoś mógłby mi to zapisać w BASIC-u? Albo w dowolnym języku tak, by było łatwo przenośne na pozostałe? A... już mam:

      lda:cmp:req 20 ->      lda 20
      -> wait cmp 20
      -> beq wait

      Powyższy zapis już rozumiem, więc raczej ogarnę :]
      • 2: CommentAuthorzbyti
      • CommentTime28 Feb 2020 12:02 zmieniony
       
      program Pause;

      uses crt;

      var rtClock : byte absolute 20;
      var frame : byte absolute $e0;
      var counter : word absolute $e2;

      begin
      counter := 0;
      frame := rtClock;
      while frame = rtClock do Inc(counter);

      rtClock := 0;

      WriteLn('Counter: ', counter);
      ReadKey;
      end.

      Wydaje się działać ;)
      • 3: CommentAuthorzbyti
      • CommentTime28 Feb 2020 12:02 zmieniony
       
      YoshPlus - kod referencyjny:

      program YoshBenchPlus;

      uses crt;

      {$define FAST}

      {$ifdef FAST}
      var i : word absolute $e0;
      var a : word absolute $e2;
      var b : word absolute $e4;
      {$else}
      var i : word;
      var a : word;
      var b : word;
      {$endif}

      var rtClock : byte absolute 20;

      begin
      i:=0;a:=0;b:=0;

      Pause;
      rtClock := 0;

      while rtClock < 100 do begin
      Inc(a); b := a;
      Inc(b); a := b;
      Inc(i);
      end;

      WriteLn('YoshPlus - iterations in 100 frames.');
      {$ifdef FAST}
      Writeln('Mad Pascal 1.6.4 opt');
      {$else}
      Writeln('Mad Pascal 1.6.4');
      {$endif}
      Writeln('Counter = ', i);
      ReadKey;
      end.

      10 A=0:B=0:I=0:F=PEEK(20)
      20 IF F=PEEK(20) THEN 20
      30 POKE 20,0
      40 IF PEEK(20)=100 THEN 100
      50 A=A+1:B=A:B=B+1:A=B:I=I+1
      60 GOTO 40
      100 ? "YOSHPLUS - INTERATIONS IN 100 FRAMES."
      110 ? "ATARI BASIC. STANDARD OS."
      120 ? "COUNTER = ";I
      • 4: CommentAuthorzbyti
      • CommentTime28 Feb 2020 16:02 zmieniony
       
      Oto moje wyniki w załączniku.

      Jeżeli ktoś poczuje potrzebę uzupełnić tabelę to niech pobierze arkusz kalkulacyjny z załącznika.

      Dołączam też ATR z binarkami kompilowanych basiców i PL65 jak ktoś chce porównać wielkość kodu wynikowego.

      Nie zmieniałem GOTO na WHILE w BASIC-ach, które bez ingerencji potrafią kompilować kod Atari BASIC.

      W BASIC-ach w których kod musiałem napisać od nowa jest pętla WHILE.
      • 5:
         
        CommentAuthorpirx
      • CommentTime28 Feb 2020 17:02
       
      Fast Basic FBI to interpreter, czy skompilowany?
      • 6: CommentAuthorzbyti
      • CommentTime28 Feb 2020 17:02 zmieniony
       
      @pirx on zawsze kompiluje źródło. "I" to od integer, możesz użyć także tego z float.
      • 7:
         
        CommentAuthorpirx
      • CommentTime28 Feb 2020 17:02
       
      nie, to nie kompilacja, tylko tokenizacja, skompilowac mozna na PC
      • 8: CommentAuthorzbyti
      • CommentTime28 Feb 2020 18:02
       
      FastBasic is one of the newest BASICs for the Atari 8-bit platform. It is a complete re-implementation of the BASIC system, using a built-in bytecode compiler rather than a tokenizing interpreter.

      ->link<-

      Nie znam się.
      • 9: CommentAuthorzbyti
      • CommentTime28 Feb 2020 23:02 zmieniony
       
      Silnia okazała się złym kierunkiem bo za szybko kończy się zakres typu liczb a mnożenie jest zbyt szybkie na benchmark ;)

      -------------------------

      Benchmark z mnożeniem

      Wymyśliłem, że sprawdzę z jaką dokładnością można wyznaczyć liczbę π za pomocą metody Monte-Carlo.

      Dla próby wielkości WORD wynik jest mocno rozczarowujący ;) ale na benchmark się nada :]

      Dla Mad Pascala zrobię jeszcze testy z optymalizacją etc. a później przeniosę na inne "znane" mi języki :]

      Może także z ciekawości sprawdzę co się da wycisnąć z CARDINAL jako "probe" ;)

      program MonteCarloPi;

      uses crt;

      var
      rtClock1 : byte absolute 19;
      rtClock2 : byte absolute 20;
      rndNumber : byte absolute $D20A;
      stop, x, y, i, r : word;
      bingo, probe : word;
      foundPi : real;

      begin
      bingo := 0;
      r := 255 * 255;
      probe := 65535;

      repeat until rndNumber <> 0;

      Pause;
      rtClock1 := 0; rtClock2 := 0;

      for i := 0 to probe do begin
      x := rndNumber; x := x * x;
      y := rndNumber; y := y * y;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * (bingo / probe);
      stop := (rtClock1 * 256) + rtClock2;

      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      WriteLn('Found pi approximation ', foundPi);
      WriteLn('Frames counter = ', stop);
      ReadKey;
      end.
      • 10: CommentAuthorzbyti
      • CommentTime28 Feb 2020 23:02 zmieniony
       
      Przy milionie losowań wynik się wiele nie poprawił :D

      Ciekawe jak dobry jest ten generator liczb pseudolosowych z POKEY'a?

      Spróbuję to puścić na PC do granicy liczby typu CARDINAL :]
      • 11: CommentAuthorzbyti
      • CommentTime28 Feb 2020 23:02 zmieniony
       
      Ha, widać sporo zależy od generatora liczb pseudolosowych!

      Przy tym samym milionie losowań na PC dostałem dość dobre przybliżenie liczby PI.

      Ktoś ma jakiś oczywisty pomysł jak usprawnić losowanie na Atari tak by w miarę łatwo było to przenośne?

      Testowo na A8 sprawdzę jeszcze polecane przez @tebe:

      RandG		Return gaussian distributed random number
      RandomRange
      RandomRangeF

      program MonteCarloPi;

      var
      i, bingo, probe : cardinal;
      r, x, y : word;
      foundPi : real;

      begin
      Randomize;

      bingo := 0;
      r := 255 * 255;
      probe := 1000000;

      for i := 0 to probe do begin
      x := Random(256); x := x * x;
      y := Random(256); y := y * y;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * (bingo / probe);

      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      WriteLn('Found pi approximation ', foundPi);
      end.

      Probe size 1000000
      Points in circle 783651
      Found pi approximation 3.1346039999999999E+000


      ------------------
      (program exited with code: 0)
      Press return to continue

      Probe size 400000000
      Points in circle 313248037
      Found pi approximation 3.1324803700000001E+000


      ------------------
      (program exited with code: 0)
      Press return to continue
      • 12:
         
        CommentAuthorbocianu
      • CommentTime29 Feb 2020 00:02 zmieniony
       
      @zbyti: może Ci się przyda do benchmarków.
      Napisałem kiedyś w MP taki test na wyliczanie daty juliańskiej, korzystając z typów zmienno i stało-przecinkowych. Może sobie do czegoś wykorzystasz ten kod.

      Tu info o algorytmie: ->link<-

      A tu kod.

      program real_vs_integer;
      uses crt, sysutils;

      const DNI = 30;
      MIES = 6;
      ILOSC = DNI * MIES;

      var miesiac, dzien: byte;
      czas1, czas2: cardinal;

      function INT_LiczDzienJulianski(rok: word; miesiac, dzien: byte): cardinal;
      var a: word;
      begin
      a := 4716 + rok + ((miesiac + 9) div 12);
      result := 367 * rok + 1729317 + dzien -
      ((a * 7) div 4) - (3 * (((a + 83) div 100) + 1) div 4) + ((275 * miesiac) div 9);
      end;

      function REAL_LiczDzienJulianski(rok: word; miesiac, dzien: byte): real;
      var a, b: real;
      begin
      a := 4716.0 + real(rok) + Int((real(miesiac) + 9.0) / 12.0);
      b := 1729279.5 + 367.0 * real(rok) + Int(275.0 * real(miesiac) / 9.0) - Int(7.0 * a / 4.0) + real(dzien);
      result := b + 38.0 - Int(3.0 * (Int((a + 83.0) / 100.0) + 1.0) / 4.0);
      end;

      begin
      Writeln(ILOSC, ' wywolan dla typu REAL');
      czas1 := GetTickCount;
      for miesiac := 1 to MIES do begin
      for dzien := 1 to DNI do begin
      REAL_LiczDzienJulianski(2017, miesiac, dzien);
      Write('.');
      end;
      Writeln;
      end;
      czas1 := GetTickCount - czas1;
      Writeln('czas wykonania: ', czas1, ' ramek');
      Writeln;

      Writeln(ILOSC, ' wywolan dla typu INTEGER');
      czas2 := GetTickCount;
      for miesiac := 1 to MIES do begin
      for dzien := 1 to DNI do begin
      INT_LiczDzienJulianski(2017, miesiac, dzien);
      Write('.');
      end;
      Writeln;
      end;
      czas2 := GetTickCount - czas2;
      Writeln('czas wykonania: ', czas2, ' ramek');
      Writeln;

      Writeln('okolo ', real(czas1) / real(czas2) ,' razy szybciej');
      ReadKey;
      end.
      • 13:
         
        CommentAuthorpirx
      • CommentTime29 Feb 2020 00:02 zmieniony
       
      @zbyti - OK, fastbasic jest kompilowany, ale na takiej zasadzie, jak java, tj. nie do 6502, ale bytecode, który jest potem interpretowany. Ale jest też do niego prawdziwny komplikator.
      W sumie ten bytecode to prawie to samo, co ztokenizowany basic, lepszy, ale idea dość podobna.
      tu leży komplikator (wymaga CC65): ->link<-

      To piszę, bo byłem ciekawy, dlaczego wyniki dla fastbasic nie są za specjalne, ale OK, bo jak na INTERPRETOWANY (jednak) basic są rewe. Ciekawe, jak wychodzi po prawdziwej komplikacji.
      • 14: CommentAuthorzbyti
      • CommentTime29 Feb 2020 00:02 zmieniony
       
      @prix pytaj, sprawdzaj, podważaj - to tylko zwiększa ogólną (moją na pewno) wiedzę :]

      Np. ja myślałem, że im więcej iteracji przy szukaniu PI tym lepiej a tymczasem, nieprawda, jest granica dla danego promienia po przekroczeniu której wynik się psuje.

      @bocianu dzięx! Jeżeli będę miał tyle zaparcia by to przepisać na pozostałe języki to skorzystam :]
      • 15: CommentAuthorzbyti
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      No i mamy coś sensownego bo jak pisałem wyżej "co za dużo to niezdrowo". OK uznaję poniższe za kod wzorcowy.

      Monte-Carlo PI kod referencyjny:
      program MonteCarloPi;

      uses crt;

      var
      rtClock1 : byte absolute 19;
      rtClock2 : byte absolute 20;
      rndNumber : byte absolute $D20A;
      stop, i, r, x, y : word;
      bingo, probe, foundPi : word;

      begin
      bingo := 0;
      r := 255 * 255;
      probe := 10000;

      Pause;
      rtClock1 := 0; rtClock2 := 0;

      for i := 0 to probe do begin
      x := rndNumber; x := x * x;
      y := rndNumber; y := y * y;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * bingo;
      stop := (rtClock1 * 256) + rtClock2;

      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      WriteLn('Found pi approximation ', foundPi / probe);
      WriteLn('Frames counter = ', stop);
      ReadKey;
      end.

      Nie we wszystkich językach mamy liczby rzeczywiste, więc dzielenie bingo / probe jest po za pomiarem czasu. W innych językach, kropkę wstawię sztuczką ;)
      • 16:
         
        CommentAuthorjhusak
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      IMHO to nie jest dobry test, bo będzie zależał od prędkości algorytmu mnożenia. Jak stablicujesz kwadraty, to program wykona się dajmy na to 15 razy szybciej.

      Druga sprawa, że liczysz na 16k punktach, więc i dokładność będzie co najwyżej rzędu 1:10000. Wziąwszy pod uwagę błedy w reprezentacji okręgu bądź co bądź na całkowitych liczbach dokładność będzie jeszcze mniejsza.

      Może lepszy byłby algorytm Bresenhama ze zliczaniem punktów na lewo i na prawo od punktu okręgu (tzn po prostu odległości od krańców obliczeń) Tam nie będzie mnożeń a sporo operacji dodawania, przypisywania, porównywania.
      • 17: CommentAuthorzbyti
      • CommentTime29 Feb 2020 01:02 zmieniony
       

      jhusak:

      bo będzie zależał od prędkości algorytmu mnożenia

      Dokładnie taki mam cel :] Napisałem o tym w pierwszym poście.

      zbyti:

      Przeprowadzę też test obliczania silni, bo wygląda na to, że procedury odpowiedzialne za mnożenie nie są jednolite i różnią się wydajnością w różnych językach.

      To co proponujesz to może jako dodatek. YoshBench chyba daje jakąś wiedzę o dodawaniu?
      • 18:
         
        CommentAuthorjhusak
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      To po prostu przetestuj 10000 mnożeń :) Na byte i card. Silnia też nie jest dobra, bo wybucha. Chyba, że reprezentacja liczb na stringach + mnożenie na stringach :) To byłoby coś :)
      • 19: CommentAuthorzbyti
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      A gdzie będzie wtedy efekt edukacyjny testu?! :D

      Dlatego zrezygnowałem z silni, na rzecz obliczania PI.
      • 20:
         
        CommentAuthorjhusak
      • CommentTime29 Feb 2020 01:02
       
      No właśnie to mnożenie na stringach.
      • 21: CommentAuthorzbyti
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      Czasem zdążę przeczytać zanim ktoś coś wyedytuje i doda info. Jak czytałem za pierwszym razem to mnożenia na stringach nie było w Twoim poście.

      Lepiej byś się wypowiedział jak poprawić randomizer w miarę prosto do implementacji ;)
      • 22:
         
        CommentAuthorjhusak
      • CommentTime29 Feb 2020 01:02
       
      Jak to? Ale o co chodzi? Jest dobry.
      • 23: CommentAuthorzbyti
      • CommentTime29 Feb 2020 01:02 zmieniony
       
      No to fajnie, bo w takim razie to co jest jest łatwo przenaszalne na inne języki ;)

      Dla zainteresowanych pogłębieniem tematu randomizacji artykuł ->link<-
      • 24:
         
        CommentAuthorjhusak
      • CommentTime29 Feb 2020 02:02
       
      Ten generator liczb losowych Atari (w Pokey) jest perełką w komputerach w ogóle. Generalnie w specjalnych zastrosowaniach robi się takie na szumiących tranzystorach czy w inny podobny sposób. Algorytmy zawsze będą w tyle.

      Parę lat temu była dziura w ssh polegająca na ograniczeniu seeda i tym samym łatwo było odgadnąć klucze, bo te wygenerowane były z wąskiej puli. Jak nic pewna agencja maczała w tym palce :)
      • 25: CommentAuthorzbyti
      • CommentTime29 Feb 2020 02:02 zmieniony
       
      @jhusak o! I takie wypowiedzi lubię czytać :]

      Tak przy okazji: Liczba pi i jej wyznaczanie ->link<- jest tam podobna metoda Monte-Carlo (do tej użytej przeze mnie) z rzucaniem igłą na druty ;)
      • 26: CommentAuthorzbyti
      • CommentTime29 Feb 2020 02:02
       
      @pirx w wątku o Action! użyłem kompilatora do FastBasic na PC i powstały program miał o 5% lepszy wynik niż ten skompilowany natywnie na A8.
      • 27: CommentAuthorzbyti
      • CommentTime29 Feb 2020 05:02 zmieniony
       
      10 BINGO=0:PROBE=10000:R=255*255:RP=53770:F=PEEK(20)
      20 IF F=PEEK(20) THEN 20
      30 POKE 20,0:POKE 19,0
      40 FOR I=0 TO PROBE
      50 X=PEEK(RP):X=X*X:Y=PEEK(RP):Y=Y*Y
      60 IF (X+Y)<=R THEN BINGO=BINGO+1
      70 NEXT I
      80 P=4*BINGO
      90 T=PEEK(20)+256*PEEK(19)
      100 ? P/PROBE;" COUNTED IN ";T;" FRAMES"
      • 28: CommentAuthortebe
      • CommentTime29 Feb 2020 08:02 zmieniony
       
      liczba PI
      (* source: CLSN PASCAL            *)
      (* This program uses a mutually *)
      (* recursive routine to calculate *)
      (* the number PI *)

      uses crt;

      function a(t: byte): single; forward;

      function b(n: byte): single;
      begin
      if (n=0) then
      b:=1/sqrt(2)
      else
      b:=sqrt(a(n-1)*b(n-1));
      end;

      function a(t:byte): single;
      begin
      if (t=0) then
      a:=1
      else
      a:=(a(t-1)+b(t-1))*0.5;
      end;

      function d(n: byte): single;
      var
      j: byte;
      s: single;
      begin
      s:=0;

      for j:=1 to n do
      s:=s+(1 shl (j+1))*(sqr(a(j))-sqr(b(j)));

      d:=1-s;
      end;

      function x_pi: single;
      const
      level=2;

      begin
      x_pi:=4*a(level)*b(level)/d(level);
      end;

      begin
      writeln('PI=',x_pi);

      repeat until keypressed;
      end.


      p.s.
      post #11, RANDOM(0) odczytuje bezpośrednio $D20A, przez co jest szybsze od RANDOM(256) które działa na programowym generatorze

      w post #15 zmieniłeś bezpośrednio na odczyt $D20A

      SINGLE ma wyższą precyzję od REAL
      • 29: CommentAuthortebe
      • CommentTime29 Feb 2020 08:02
       
      #15, dobry benchmark

      dodając {$f $70} można przekonać się o ile przyspieszą szybkie procedury mnożenia (umieszczone od strony pamięci $70}
      • 30: CommentAuthorzbyti
      • CommentTime29 Feb 2020 11:02 zmieniony
       
      @tebe

      1. tak dziś miałem zamiar puścić Mad Pascal ze zmiennymi na stronie zerowej, z szybkim mnożeniem i jedno i drugie na raz :]

      2. odczytuje bezpośrednio z $D20A by w każdym innym języku mieć takie same szanse na liczbę losową, bez względu na to jaką mają ich implementację. W poście #11 to na potrzeby Free Pascala i wykonani testu na PC.

      3. nie chcę używać ani SINGLE ani REAL bo chcę liczyć na liczbach całkowity i mieć jakieś porównanie np. do Action! oraz mu podobnych, kompilować tymi BASIC-ami co na to pozwalają z opcją INTEGER etc. Dlatego dzielenie przez PROBE jest dopiero jak drukuję wynik po za pomiarem czasu. W Action! np. po prostu dorysuję "," w odpowiednie miejsce liczby CARD ;) Rozumiem, że ta uwaga o precyzji przyda mi się do kodu we Free Pascalu.

      4. Z tego samego powodu co pkt.3 nie zdecydowałem się na metody szukania PI gdzie używa się pierwiastków etc.

      Fajnie że spodobał ci się ten benchmark. Liczę na dalsze podpowiedzi z Twojej strony :]
      • 31: CommentAuthorzbyti
      • CommentTime29 Feb 2020 11:02 zmieniony
       
      program MonteCarloPi;

      uses crt;

      {$define FAST}
      {$f $70}

      var
      rtClock1 : byte absolute 19;
      rtClock2 : byte absolute 20;
      rndNumber : byte absolute $D20A;

      {$ifdef FAST}
      stop : word absolute $e0;
      i : word absolute $e0;
      r : word absolute $e2;
      x : word absolute $e4;
      y : word absolute $e6;
      bingo : word absolute $e8;
      probe : word absolute $ea;
      foundPi : word absolute $ec;
      {$else}
      stop, i, r, x, y : word;
      bingo, probe, foundPi : word;
      {$endif}

      begin
      bingo := 0;
      r := 255 * 255;
      probe := 10000;

      Pause;
      rtClock1 := 0; rtClock2 := 0;

      for i := 0 to probe do begin
      x := rndNumber; x := x * x;
      y := rndNumber; y := y * y;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * bingo;
      stop := (rtClock1 * 256) + rtClock2;

      {$ifdef FAST}
      WriteLn('Variables on zero page');
      {$endif}
      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      WriteLn('Found pi approximation ', foundPi / probe);
      WriteLn('Frames counter = ', stop);
      ReadKey;
      end.

      Na screenach w kolejności:

      1. bez optymalizacji
      2. zmienne na stornie zerowej
      3. szybkie mnożenie bez zmiennych na stronie zerowej
      4. szybkie mnożenie ze zmiennymi na stronie zerowej.
      • 32: CommentAuthorzbyti
      • CommentTime29 Feb 2020 12:02 zmieniony
       
      Turbo BASIC XL skompilowany, pracuje na liczbach rzeczywistych.
      • 33: CommentAuthorzbyti
      • CommentTime29 Feb 2020 12:02 zmieniony
       
      ABC BASIC Compiler

      Przy okazji odkryłem, że on jedzie tylko na liczbach całkowitych, ale sztuczka z "dorysowaniem" kropki działa ;)
      • 34: CommentAuthorzbyti
      • CommentTime29 Feb 2020 12:02
       
      MMG Basic Compiler po wybraniu podczas kompilacji INTEGER oddaje takie coś jak na ekranie. Nie wiem czy ma INT ze znakiem czy co tam się dzieje, dlatego nie umieszczę w zestawieniu.
      • 35: CommentAuthorzbyti
      • CommentTime29 Feb 2020 13:02 zmieniony
       
      Niestety FastBasic też operuje na:

      Integer from -32768 to 32767.

      Przejdę w takim razie na floating point co oznacza, że po nazwie zmiennej muszę dokleić znak '%'.

      Być może będę musiał powtórzyć test dla Advan Basic bo tam jest ta sama konwencja zapisu, i być może robi to samo, więc możliwe, że robiłem dodawania na zmiennoprzecinkowych a nie na całkowitych.

      EDIT 1: a olać, nie będę mieszał typów. Skoro ma takie ograniczenie to FastBasic na razie wypada z testu.

      EDIT 2: ha, ha, he.... nie muszę powtarzać testu z Advan Basic bo tam '%' oznacz właśnie całkowitą. Odwrotnie jak w FastBasic.

      EDIT 3: Advan BASIC ma to samo organicznie dla INT
      • 36: CommentAuthorzbyti
      • CommentTime29 Feb 2020 14:02 zmieniony
       
      Advan BASIC z float, optymalizacja nie jest już wtedy tak szokująca jak przy całkowitych.
      • 37: CommentAuthorzbyti
      • CommentTime29 Feb 2020 15:02 zmieniony
       
      W FastBasic i Action! coś nie pyka i PI dostaję blisko liczby 4. Nie chce mi się tego rozkminiać, więc na ten moment tylko BASIC Vs. Mad Pascal :]

      Jak w ruch idzie mnożenie to przewaga już nie jest tak duża jak w poprzednich testach SIEVE czy YoshPlus.

      Jak @ilmenit zechce to walnie to w CC65 ;)

      Po wynikach to można sądzić, że jak piszemy w BASIC-u i używamy dużo mnożeń to najlepszym wyborem będzie TURBO BASIC XL.

      To ciekawe biorąc wyniki TB XL gdzie były same dodawania. Jak zwykle warto dobierać narzędzie do zadania :]
      • 38: CommentAuthorzbyti
      • CommentTime29 Feb 2020 17:02 zmieniony
       
      OK.

      Poniższy kod, przy odrobinie szczęścia będzie działał w językach z typem całkowitym ze znakiem.

      Jeżeli przekroczę 32000 to tylko dlatego, że kompilator coś oszukiwał z pobieraniem wartości losowej z POKEY'a.

      Na końcu sztuczka z przecinkiem dla języków gdzie nie ma typów rzeczywistych i nie można sobie wygodnie podzielić bingo / probe.

      Wydaje mi się to teraz całkiem przenośne i nie wymaga przy poprawnym losowaniu liczb większych niż 32000.

      program MonteCarloPi;

      uses crt;

      {$define FAST}
      {$f $70}

      var
      rtClock1 : byte absolute 19;
      rtClock2 : byte absolute 20;
      rndNumber : byte absolute $D20A;

      {$ifdef FAST}
      stop : word absolute $e0;
      i : word absolute $e0;
      r : word absolute $e2;
      x : word absolute $e4;
      y : word absolute $e6;
      bingo : word absolute $e8;
      probe : word absolute $ea;
      foundPi : word absolute $ec;
      n : byte absolute $ee;
      {$else}
      stop, i, r, x, y : word;
      bingo, probe, foundPi : word;
      n : byte;
      {$endif}

      begin
      bingo := 0;
      r := 127 * 127;
      probe := 10000;

      Pause;
      rtClock1 := 0; rtClock2 := 0;

      for i := 0 to probe do begin
      n := (rndNumber or %10000000) xor %10000000;
      x := n * n;
      n := (rndNumber or %10000000) xor %10000000;
      y := n * n;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * bingo;
      stop := (rtClock1 * 256) + rtClock2;

      {$ifdef FAST}
      WriteLn('Variables on zero page');
      {$endif}
      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      Write('Found pi approximation ', foundPi);
      WriteLn(chr(30),chr(30),chr(30),chr(30),chr(255),chr(44));
      WriteLn('Frames counter = ', stop);
      ReadKey;
      end.
      • 39: CommentAuthorzbyti
      • CommentTime29 Feb 2020 18:02 zmieniony
       
      • 40: CommentAuthorzbyti
      • CommentTime29 Feb 2020 19:02 zmieniony
       
      OK. No to jadę drugą turę, z pominięciem Atari BASIC.

      Turbo BASIC XL

      10 PROBE=10000:BINGO=0:R=127*127:RP=53770:F=PEEK(20)
      20 IF F=PEEK(20) THEN 20
      30 POKE 20,0:POKE 19,0
      40 FOR I=0 TO PROBE
      50 N=PEEK(RP):N=N!128:N=N EXOR 128:X=N*N
      55 N=PEEK(RP):N=N!128:N=N EXOR 128:Y=N*N
      60 IF (X+Y)<=R THEN BINGO=BINGO+1
      70 NEXT I
      80 P=4*BINGO
      90 T=PEEK(20)+256*PEEK(19)
      100 ? P;CHR$(30);CHR$(30);CHR$(30);CHR$(30);CHR$(255);CHR$(46)
      110 ? T;" FRAMES"
      • 41: CommentAuthorzbyti
      • CommentTime29 Feb 2020 20:02 zmieniony
       
      Action! 3.7P

      BYTE RTCLOCK2=20
      BYTE RTCLOCK1=19
      BYTE RNDPOKEY=$D20A

      BYTE N
      CARD BINGO,I,X,Y,P,T
      CARD PROBE=[10000]
      CARD RADIUS=[16129]

      PROC main()
      X=0 Y=0 BINGO=0
      N=RTCLOCK2
      WHILE N=RTCLOCK2 DO OD
      RTCLOCK1=0 RTCLOCK2=0
      FOR I=0 TO PROBE
      DO
      N=(RNDPOKEY % 128) ! 128
      X=N*N
      N=(RNDPOKEY % 128) ! 128
      Y=N*N
      IF (X+Y)<=RADIUS THEN BINGO==+1 FI
      OD
      P=4*BINGO
      T=RTCLOCK2+(RTCLOCK1*256)

      PRINTE("Mone-Carlo Pi in Action! 3.7P")
      PRINT("Pi approximation = ") PRINTC(P)
      PUT(30) PUT(30) PUT(30) PUT(30) PUT(255) PUT(46) PUTE()
      PRINTF("Frames = %U%E",T)
      RETURN
      • 42: CommentAuthorzbyti
      • CommentTime29 Feb 2020 20:02 zmieniony
       
      Mad Pascal 1.6.4
      program MonteCarloPi;

      uses crt;

      {$define FAST}
      {$f $70}

      var
      rtClock1 : byte absolute 19;
      rtClock2 : byte absolute 20;
      rndNumber : byte absolute $D20A;

      {$ifdef FAST}
      stop : word absolute $e0;
      i : word absolute $e0;
      r : word absolute $e2;
      x : word absolute $e4;
      y : word absolute $e6;
      bingo : word absolute $e8;
      probe : word absolute $ea;
      foundPi : word absolute $ec;
      n : byte absolute $ee;
      {$else}
      stop, i, r, x, y : word;
      bingo, probe, foundPi : word;
      n : byte;
      {$endif}

      begin
      bingo := 0;
      r := 127 * 127;
      probe := 10000;

      Pause;
      rtClock1 := 0; rtClock2 := 0;

      for i := 0 to probe do begin
      n := (rndNumber or %10000000) xor %10000000;
      x := n * n;
      n := (rndNumber or %10000000) xor %10000000;
      y := n * n;
      if (x + y) <= r then Inc(bingo);
      end;

      foundPi := 4 * bingo;
      stop := (rtClock1 * 256) + rtClock2;

      {$ifdef FAST}
      WriteLn('Variables on zero page');
      {$endif}
      WriteLn('Probe size ', probe);
      WriteLn('Points in circle ', bingo);
      Write('Found pi approximation ', foundPi);
      WriteLn(chr(30),chr(30),chr(30),chr(30),chr(255),chr(44));
      WriteLn('Frames counter = ', stop);
      ReadKey;
      end.
      • 43: CommentAuthorzbyti
      • CommentTime29 Feb 2020 20:02 zmieniony
       
      Mad Pascal RuLeZ! :]

      Jak mnie natchnie to dopiszę w jeszcze paru językach ten benchmark.
      • 44: CommentAuthorzbyti
      • CommentTime29 Feb 2020 22:02
       
      FastBasic 4.0 FBI

      PROBE=10000:B=0:R=127*127:F=PEEK(20)
      WHILE F=PEEK(20)
      WEND
      POKE 20,0:POKE 19,0
      FOR I=0 TO PROBE
      N=PEEK($D20A):N=N!128:N=N EXOR 128
      X=N*N
      N=PEEK($D20A):N=N!128:N=N EXOR 128
      Y=N*N
      IF (X+Y)<=R THEN INC B
      NEXT I
      P=4*B
      T=TIME
      ? P;CHR$(30);CHR$(30);CHR$(30);CHR$(30);CHR$(255);CHR$(46)
      ? T;" FRAMES"
      • 45: CommentAuthorzbyti
      • CommentTime29 Feb 2020 23:02 zmieniony
       
      Advan BASIC

      Nie miałem w Advan instukcji XOR więc użyłem MOD. Jak wróciliśmy do liczb całkowitych to Advan BASIC pokazuje pazury :]

      W Mad Pascalu zastąpienie dwóch instrukcji OR i XOR wywołaniem RAND MOD 128 skutkuje pogorszeniem osiągów.

      Wyniku spada dla najszybszej opcji ze 120 do 282 ramek.
      • 46: CommentAuthorzbyti
      • CommentTime29 Feb 2020 23:02 zmieniony
       
      • 47: CommentAuthorzbyti
      • CommentTime1 Mar 2020 18:03 zmieniony
       
      Quick 2.2

      Quick-Sourcetext
      D2:PI.QIK
      ----------------
      Length: $0233

      Free : $7538
      ----------------

      BYTE
      [
      RTC1=19
      RTC2=20
      RNDP=$D20A
      N
      ]

      WORD
      [
      B,I,X,Y,P,T,PR,RA,XY
      ]

      ARRAY
      [
      FIELD(8)
      ]

      MAIN
      PR=10000
      RA=16129
      X=0
      Y=0
      B=0
      I=0

      N=RTC2
      WHILE N=RTC2
      WEND
      RTC2=0
      RTC1=0

      WHILE I<PR
      OR(RNDP,128,N)
      EOR(N,128,N)
      MULT(N,N,X)
      OR(RNDP,128,N)
      EOR(N,128,N)
      MULT(N,N,Y)
      ADD(X,Y,XY)
      IF XY<=RA
      ADD(B,1,B)
      ENDIF
      ADD(I,1,I)
      WEND
      MULT(4,B,P)
      MULT(RTC1,256,T)
      ADD(RTC2,T,T)

      FIELD(0)=30
      FIELD(1)=30
      FIELD(2)=30
      FIELD(3)=30
      FIELD(4)=30
      FIELD(5)=255
      FIELD(6)=46
      FIELD(7)=0
      ?("PI = ",P,FIELD)
      ?("FRAMES = ",T)
      ENDMAIN
      • 48: CommentAuthorzbyti
      • CommentTime1 Mar 2020 20:03 zmieniony
       
      Zaktualizowałem Mad Pascala 1.6.4, ostatnie zmiany są z przed 5 godzin.

      Monte-Carlo PI przyspieszyło o 5% w stosunku do wersji master z przed miesiąca :]
      • 49: CommentAuthorzbyti
      • CommentTime2 Mar 2020 00:03 zmieniony
       
      Jako, że @ilmenit gdzieś znikł to trzeba sobie radzić ;)

      cl65 -t atari -o mcpi.xex mcpi.c           602 ticks
      cl65 -t atari -Osir -Cl -o mcpi.xex mcpi.c 303 ticks

      Flagi kompilatora do rozczytania tutaj: ->link<-

      #include <stdio.h>

      void main(void)
      {
      register unsigned int stop, i, x, y;
      register unsigned int b, p, r;
      register unsigned char n;
      register unsigned char* rndp = 0xd20a;
      register unsigned char* tick = 0x14;
      register unsigned char* tack = 0x13;

      b = 0;
      r = 127 * 127;
      p = 10000;

      n = *tick;
      while (*tick == n) { ; }

      printf("\nMonte-Carlo PI cc65 V2.18\n");

      asm(" lda #0");
      asm(" sta $13");
      asm(" sta $14");

      for (i = 0 ; i < p; ++i)
      {
      n = (*rndp | 128) ^ 128;
      x = n * n;
      n = (*rndp | 128) ^ 128;
      y = n * n;
      if ((x + y) <= r)
      ++b;
      }
      b = 4 * b;
      stop = *tick + (*tack * 256);

      printf("%d%c%c%c%c%c%c\n", b, 30, 30, 30, 30, 255, 46);
      printf("%d ticks\n", stop);

      infinite:
      goto infinite;
      }

      Albo coś źle napisałem w C (to mój pierwszy kod) albo Mad Pascal z szybkim mnożeniem jest sporo szybszy od zoptymalizowanego CC65.

      A bez szybkiego mnożenia i tak jest wciąż znacznie szybszy od zoptymalizowanego CC65.

      W dodawaniu "na potęgę" ;D przewagę wciąż ma CC65, jak już wcześniej pokazaliśmy.

      W tabelce jeszcze nie podbiłem o te 5% wyników Mad Pascala (dzisiejsza kompilacja), ale można sobie od każdego jego wyniku odjąć ~10 ramek ;)
      • 50: CommentAuthorzbyti
      • CommentTime2 Mar 2020 01:03 zmieniony
       
      #include <stdio.h>
      #include <peekpoke.h>

      #define tick 0x14
      #define tack 0x13
      #define rndp 0xd20a

      void main(void)
      {
      register unsigned int stop, i, x, y;
      register unsigned int b, p, r;
      register unsigned char n;

      b = 0;
      r = 127 * 127;
      p = 10000;

      n = PEEK(tick);
      while (PEEK(tick) == n) { ; }

      printf("\nMonte-Carlo PI cc65 V2.18\n");

      asm(" lda #0");
      asm(" sta $13");
      asm(" sta $14");

      for (i = 0 ; i < p; ++i)
      {
      n = (PEEK(rndp) | 128) ^ 128;
      x = n * n;
      n = (PEEK(rndp) | 128) ^ 128;
      y = n * n;
      if ((x + y) <= r)
      ++b;
      }
      b = 4 * b;
      stop = PEEK(tick) + (PEEK(tack) * 256);
      printf("%d%c%c%c%c%c%c\n", b, 30, 30, 30, 30, 255, 46);
      printf("%d ticks\n", stop);

      infinite:
      goto infinite;
      }

      PEEK trochę przyspiesza wykonywanie kodu (na screenie kompilacja z optymalizacją), myślałem, że pointer będzie szybszy.

      Tam się odbywa to niejawne rzutowanie?

      O tyle samo się poprawia wynik Mad Pascala gdy puszczam benchmark kompilacją MP z dzisiaj, więc tabelka jest OK ;)