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 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 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 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 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
     
    Fast Basic FBI to interpreter, czy skompilowany?
    • 6: CommentAuthorzbyti
    • CommentTime28 Feb 2020 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
     
    nie, to nie kompilacja, tylko tokenizacja, skompilowac mozna na PC
    • 8: CommentAuthorzbyti
    • CommentTime28 Feb 2020
     
    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 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 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 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 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 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 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 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 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 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 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 zmieniony
     
    A gdzie będzie wtedy efekt edukacyjny testu?! :D

    Dlatego zrezygnowałem z silni, na rzecz obliczania PI.
    • 20:
       
      CommentAuthorjhusak
    • CommentTime29 Feb 2020
     
    No właśnie to mnożenie na stringach.
    • 21: CommentAuthorzbyti
    • CommentTime29 Feb 2020 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
     
    Jak to? Ale o co chodzi? Jest dobry.
    • 23: CommentAuthorzbyti
    • CommentTime29 Feb 2020 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
     
    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 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
     
    @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 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 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
     
    #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 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 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 zmieniony
     
    Turbo BASIC XL skompilowany, pracuje na liczbach rzeczywistych.
    • 33: CommentAuthorzbyti
    • CommentTime29 Feb 2020 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
     
    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 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 zmieniony
     
    Advan BASIC z float, optymalizacja nie jest już wtedy tak szokująca jak przy całkowitych.
    • 37: CommentAuthorzbyti
    • CommentTime29 Feb 2020 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 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 zmieniony
     
    • 40: CommentAuthorzbyti
    • CommentTime29 Feb 2020 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 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 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 zmieniony
     
    Mad Pascal RuLeZ! :]

    Jak mnie natchnie to dopiszę w jeszcze paru językach ten benchmark.
    • 44: CommentAuthorzbyti
    • CommentTime29 Feb 2020
     
    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 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 zmieniony
     
    • 47: CommentAuthorzbyti
    • CommentTime1 Mar 2020 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 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 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 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 ;)