atarionline.pl Mały quiz informatyczny - 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: CommentAuthormarok
    • CommentTime23 Dec 2022 zmieniony
     
    Mały quiz, raczej dla informatyków. (Sam bym nie zgadł, ale informatykiem nie jestem.)

    Czy ten wzór graficzny się komuś z czymś może kojarzy?
    • 2:
       
      CommentAuthorKaz
    • CommentTime24 Dec 2022
     
    Mnie się kojarzy z demem "Drunk Chessboard", ale pewnie nie o to Ci chodzi :)
  1.  
    mi się kojarzy z "dywanem Sierpińskiego". ->link<-

    ale takie rozwiązanie powoduje, że pytanie jest bardziej do matematyków teoretycznych.
    • 4:
       
      CommentAuthorjhusak
    • CommentTime24 Dec 2022 zmieniony
     
    Okno z firanką.
    Śnieg na morzu.
    Pogoda w kratkę.
    Z powiększonym fontem - 4 kółeczka z czego na skos 2 w inwersie w matrycy 8x8 punktów, po kolei 4 sztuki: znak normalny, inwers, inwers, normalny.
    • 5: CommentAuthormarok
    • CommentTime24 Dec 2022 zmieniony
     
    Dzięki za wpisy!

    Ja sobie powolutku przygotowywałem taką jeszcze podpowiedź (zanim spostrzegłem większą ilość komentarzy).


    Skojarzenie z szachownicą jest naturalne. Powodem jest zachowana duża regularność wizualna wzoru.

    Zwrócę jeszcze uwagę (zachęcam tak do podjęcia wyzwania), że ekran z poprzedniego obrazka, jest ustawiony na wąski (32 pozycje w poziomie), a każda linia patrząc poziomo czy pionowa, ma dokładnie połowę znaków zapalonych, a połowę zgaszonych ( (16+16) * (4+4) = 256 ). Z tego właśnie bierze się wspomniana regularność wizualna.

    Ogólnie, to jest nie za skomplikowana łamigłówka na spostrzegawczość (można ambicjonalnie do tego podejść i potraktować to jako test wart zaliczenia, na inteligencję). A rozwiązanie nie "z kosmosu", tylko spokojnie jednak "do wyczajenia" (przy pewnym wysiłku). (Wspominałem wczoraj o informatykach - że to właściwie do nich skierowany "quiz", dlatego że mieli potencjalnie dużo większą szansę zwizualizować sobie ten "algorytm", przy jakiejś tam sposobności wcześniej. A więc skorzystać na tą okazję z zapamiętanych "obrazów". Stąd ich główna może brać się przewaga.)


    W celach porównawczych, to obraz z danych wynikowych dokładnie tych samych (to samo), ale wyświetlony na ekranie "normalnym" (40 znaków). Układa się już w mniej "regularny" wizualnie wzór.
    • 6:
       
      CommentAuthorjhusak
    • CommentTime24 Dec 2022 zmieniony
     
    Pytanie, "z czym Ci się kojarzy" jest inne, niż "podaj rozwiązanie tej łamigłówki".
    • 7:
       
      CommentAuthorgienekp
    • CommentTime24 Dec 2022 zmieniony
     
    Pamiętam jak w jakimś teście na inteligencję, w info było napisane, że odpowiedź można zaliczyć, jeżeli ma ona logiczne wyjaśnienie. :) Taka furtka jakby się okazało, że testowany jest zbyt bystry względem testującego.

    Więc:
    Podaj następną liczbę dla 1, 2, 3
    a) 4
    b) 3
    c) 1.23456789

    :)

    Wszystkie odpowiedzi są dobre i w zasadzie każda dowolna liczba, ponieważ istnieje nieskończenie wiele wielomianów, których miejsca zerowe są w 1 2 3 i dowolnej innej liczbie. ;)
    • 8: CommentAuthormarok
    • CommentTime24 Dec 2022
     
    @jhusak

    Bez wątpienia to celne i na miejscu wytknięcie mojej niekonsekwencji.

    Na pewne usprawiedliwienie: odwoływałem się wpierw do "informatyków", bo sądziłem że mogą kojarzyć obraz z tym, co mają szansę pamiętać ze swoich doświadczeń (takie moje domniemanie wstępne). A więc użycie słowa "skojarzenie" miało formalnie swoją jakąś "rację bytu".

    Ponieważ, jednak, nie jest to moje domniemanie oparte na żadnej znajomości zbiorowych doświadczeń informatyków, to w drugiej fazie swojej pełniejszej wypowiedzi, przekierowałem uwagę na analityczny aspekt możliwości rozpoznania tego, co to jest (co przedstawia obraz). W sumie, nie ważne jak, ale chciałbym doprowadzić do wyjaśnienia tego quiza ("czego obrazem to jest"). Mam w tym taki interes, że chodzi mi o przedstawienie prostego rozwiązania, które dalej można jeszcze ulepszyć. A że można, to sprawdziłem, ale jest to na tyle mało intuicyjne "z pierwszego wejrzenia" (że w ogóle można), że chciałem podzielić się przy okazji jakimś przesłaniem ogólnym związanym z rozwiązywaniem problemów "programistycznych" (o czym innym razem). No i chciałem też zaprosić do przemyślenia samodzielnie, czy z wersji wyjściowej rozwiązania zadania, da się to zrobić lepiej. A dopiero na koniec przedstawić rozwiązanie (dla mnie) lepsze.


    Pisząc krótko i "zachęcająco" (to mi przyświecało) zapewne jednak uchybiłem rzetelnemu przedstawieniu swoich pełnych intecji, co do planowanych "zagadywań" forumowiczów. Mogę przeprosić, ponieważ później zaczęłem trochę wchodzić czytającym te moje wywody na ambicję - można by napisać - aby się sprawą rozwiązania tej zagadki raczyli jednak zająć trochę poważniej (niż zupełnie przelotnie).
    • 9: CommentAuthormarok
    • CommentTime24 Dec 2022
     
    Pamiętam jak w jakimś teście na inteligencję, w info było napisane, że odpowiedź można zaliczyć, jeżeli ma ona logiczne wyjaśnienie. :) Taka furtka jakby się okazało, że testowany jest zbyt bystry względem testującego.


    Pytający stawia się w roli uprzywilowanej, ale w rzeczywistości faktycznie nie ma na to żadnej gwarancji, że jest "bystrzejszy" niż odpytywany. Sam powinien o tym pamiętać - zgadzam się.

    Z kolei mi się przypomina, że pod testem na inteligencję, czy cokolwiek innego, znajdowała się informacja niezwykle dla mnie kluczowa, otóż że zadanie na pewno ma rozwiązanie (dokładnie spełniające to, o jakie w pytaniu chodzi). Trzeba je *tylko* znaleźć. To mobilizowało do wydajniejszego "główkowania" i nie poddawania się pierwszemu złudzeniu swojej nieosiągalności. Sama taka zachęta często ma decydujące znaczenie, czy się rozwiązanie znajdzie już "w danym podejściu", czy się je odłoży na inny raz, nie będąc przekonanym w ogóle, czy zadanie ma swoje prawidłowe rozwiązanie.



    To all. Jeśli nie odpisuję na dany koment, to znaczy że skojarzenie podawane w odpowiedzi jest dalekie od tego, czym to jest. Więc nic nie piszę, bo to chyba najlepsza mimo wszytko forma komunikacji w takich razach. (Tak twierdzić by mogło przynajmniej "Ministerstwo diagnozowania zbędnych ruchów i przepływów informacji". To ostatnie, to miał być żart. Pozdrawiam.)
    • 10:
       
      CommentAuthorpirx
    • CommentTime24 Dec 2022
     
    mi się kojarzy z fellatio, ale może dlatego, że jak jednemu szeregowemu wszysztko mi się z jednym kojarzy :]]]
    • 11:
       
      CommentAuthorPeri Noid
    • CommentTime24 Dec 2022
     
    Mi się to kojarzy z grą w życie. Wzór przypomina kombinacje stabilne.
    • 12: CommentAuthorZenon
    • CommentTime24 Dec 2022
     
    Jak to coś jest dla informatyków to jest to graficzna reprezentacja funkcji NOT.
    Górna połówka obrazka jest negacją dolnej, albo dolna jest negacją górnej.
    Kto by tam wiedział jak zacząć....
    • 13: CommentAuthormarok
    • CommentTime24 Dec 2022 zmieniony
     
    @Zenon: Jesteś już całkiem blisko prawidłowej odpowiedzi.

    @Peri Noid, @pirx: Szczerze, to muszę zapoznać się dopiero z terminami: "gra w życie", "kombinacja stabilna" i "fellatio" (ten ostatni, to się trochę obawiam sprawdzać nawet, bo jakoś tak dziwnie nie się kojarzy).

    Chociaż ta "kombinacja stabilna" brzmi przystająco na mój gust (zgaduję więc w ciemno, że to prawidłowe przypisanie).

    EDIT:
    "grę w życie" pobieżnie już kiedyś widziałem (b. ogólnie pojmuję mechanizm działania gry), ale w pierwszym momencie nie skojarzyłem, że to o to może chodzić (dla mnie to dość odległe skojarzenie - może dlatego, ale mogę nie znać zbyt dobrze tej gry, z drugiej strony);
    "kombinacja stabilna": dokładnie takiego terminu nie znalazłem, więc przypuszczam że jest on nieprecyzyjny, choć brzmi całkiem rozsądnie (i jak pisałem, całkiem adekwatnie);
    "fellatio": dobra już wiem; skojarzyło mi się (pewnie suma czynników) z wymiocinami, więc tak zupełnie to odległe nie było ("się pochwalę").
    • 14:
       
      CommentAuthorgienekp
    • CommentTime24 Dec 2022 zmieniony
     
    A tak w ogóle, jakby mi ktoś takie coś podesłał, z prośbą o "złamanie". To te kropki zamieniłbym na jeden ciąg zer i jedynek. Potem test czy pasuje 2 bity czy 3 czy 4. Zrobienie z tego liczb i FFT czy jakaś okresowość. Zwykle po tym wiadomo, czy to fragment obrazu, dźwięku czy inny kod kreskowy.
    • 15: CommentAuthormarok
    • CommentTime24 Dec 2022
     
    A tak w ogóle, jakby mi ktoś takie coś podesłał, z prośbą o "złamanie". To te kropki zamieniłbym na jeden ciąg zer i jedynek.

    I to jest bardzo dobra koncepcja.

    Dalszego ciągu rozumowanie deklaruję że nie ogarniam, ale być może robi różnicę to, że to Ty pewnie jesteś informatyk - w przeciwieństwie do mnie (znów o tym piszę, że nie jestem informatykiem, no coż - jakieś kompleksy może).

    Kropki są na tyle duże, że można je sobie "zeskanować" ("gołym wzrokiem") do ciągu, o którym piszesz (choć nie jest to wygodne, z drugiej strony może nie jest też konieczne).

    Ja tylko jeszcze zauważę, że prowadząc linię poziomą przez środek zakreślonego obrazu (o czym pisał już Zenon) uzyskujemy lustrzane odbicia - obie połówki nakładają się na siebie w inwersie (co oznacza, że po takim nałożeniu, kropki traktowane jako 0 i 1 zawsze nachodziłyby na siebie nawzajem; wychodziłoby z tego nałożenia, że zawsze daje to 1 - czyli "już po" połówka obrazu wzdłuż "linii lustra" byłaby w inwersie, a połówka obrazu byłaby pusta - bo się przecież złożyła - obróciła wzdłuż linni lustra, czyli przemieściła w całości; to taka wizualizacja do przeprowadzenia w wyobraźni, ale raczej prosta). Dodać do tego można, że to samo dotyczy podziału pionowego przez środek obrazu - znów mamy "lustro w inwersie".

    Na tą chwilę dalej nie podpowiadam. :)
    • 16:
       
      CommentAuthorgienekp
    • CommentTime24 Dec 2022
     
    Nie, nie jestem informatykiem, tylko pasjonatem wczesnej informatyki. ;) A z informatykami lubię się droczyć, bo to stymulująco intelektualne wyzwanie. :)
    • 17: CommentAuthormarok
    • CommentTime24 Dec 2022
     
    A to przy okazji dzięki za informację. (Z nie-informatykami też się można okazjonalnie podroczyć o kwestie informatyczne. Może to nie to samo, ale jednak.)
    • 18: CommentAuthormarok
    • CommentTime25 Dec 2022 zmieniony
     
    Nowy dzień, nowe "marudzenie". (Dziś ta część quiza, która dotyczy istoty prezentowanego obrazu, zostanie z pewnością odgadnięta lub przeze mnie podana.)


    Jako podpowiedź, słowo klucz: uporządkowanie.

    Uporządkowanie powinno nieodłącznie kojarzyć się z działaniem każdego programu, ponieważ:
    - ma to sens, bo dopiero wtedy jest czytelne, zwłaszcza kiedy ma być czytelne (jak w tym przypadku - w końcu to zagadka do rozwiązania, a nie do nierozwiązania),
    - jest to w oczywisty sposób naturalne i najprostsze od strony samego oprogramowania,

    Tak na prawdę uporządkowanie rozumiane jako algorytm postępowania, jest bezwzględnie konieczne, aby program coś konkretnego (cokolwiek!) czynił. Ale w tym przypadku piszę o uporządkowaniu najbardziej oczywistym, jakie się narzuca każdemu, kto pisze programy. Nazwijmy to tak, o uporządkowaniu kroczącym; a oprócz tego - danego problemu, w tym sensie, że ogarnia to całość badanego zagadnienia (zauważcie, że właśnie tak zostało to przedstawione), co można przełożyć zwykle na wszystkie wariancje/ kombinacje. A jeśli mamy dokładnie 256 punktów obrazu to skojarzenie tego z pojemnością bajta powinno być już czysto banalnym przypisaniem (domyślne na poziomie oczywistości).

    Ostatnią podpowiedzią jest to, że obraz jest symetryczny względem dowolności wyboru kierunku prezentacji: od przodu/ od tyłu (lewy górny róg - przód, prawy dolny róg - tył). Znaczy to tyle, że punkt ostatni jest identyczny z punktem pierwszym, PO-1 = PP+1, itd.

    Chociaż jeszcze jedna (*bold*) podpowiedź:
    Nie ma obok siebie więcej niż 2 punktów takich samych, zawsze potem następuje revers wartości poprzedniego punktu (i ew. jeszcze poprzedniego, jeśli wartości tych obu są sobie równe). Warto zwrócić jeszcze uwagę na to, na jakich pozycjach *tylko* rozpoczynają się ciągi 2-punktowe takich samych wartości.
    • 19: CommentAuthormarok
    • CommentTime26 Dec 2022
     
    Rozwiązanie.

    Obraz to zrzut wyniku tzw. bitu "parity" dla kolejnych wartości bajta z jedną tylko drobną poprawką, że jest on zawsze odwrócony od swojej wartości "nominalnej" (kiedy miałby być zapalony, tu jest zgaszony, i odwrotnie). Jest to wygodniejsze w tej formie do zaprogramowania na 6502 z mojej perspektywy (chociaż niekoniecznie w wersji tzw. wyjściowej).

    Bit "parity" (chyba wszyscy to wiedzą) zaś to taki bit z niektórych innych procesorów niż 6502, który określa czy liczba bitów (z 8) obu możliwych stanów (a tym samym każdego z osobna) jest parzysta, czy przeciwnie (nieważne w jakim podziale tych 8).


    Zadanie ustalenia tego (wirtualnego) bitu polega zwykle, jak sądzę, na zliczeniu (z tzw. rozpędu i przy okazji) bitów o ustalonym stanie - zlicza się ustawione, bọ… , a z tej liczby interesujące jest tylko, czy to liczba parzysta czy nie.


    Jest to więc wszystko bardzo proste w założeniu, ale mimo wszystko dość czasochłonne w działaniu.


    Cały kod procedury w wersji wyjściowej (dość oczywisty) razem z obsługą wyświetlania wyników (obrazu), mieści się w tym:

    org $1000

    ldy $d40b
    bne *-3
    loop tya
    jsr parS
    lda #0
    ror @
    sta ($58),y
    iny
    bne loop
    loop2
    lda #32
    and $14
    cmp #1
    lda $022f
    and #$fc
    adc #1
    sta $d400
    bcc loop2


    parS ldx #-1 ;0
    ;parS dta {ldx #}
    par1 inx
    par2 lsr @ ;asl @
    bcs par1
    bne par2
    txa
    lsr @
    rts



    parS to miejsce początku i jednocześnie wejścia do procedury właściwej przekształcającej wartość bajta z akumulatora na bit parity.

    Zdedydowałem się zamieścić już teraz linię zaremowanego kodu z poprawką udoskonalającą ten kod procedury wyjściowej (skraca go o 1, a przyspiesza o +~1%). Ponieważ okazało się, że przegapiłem to na samym początku. A punktem wyjścia była dla mnie wersja bez tego udoskonalenia (do niej też odnosiłem się za każdym razem, jako do tej wyjściowej).


    Jutro już może podam wersję szybszą o +~10% (od wyjściowej), choć nieco dłuższą.


    Co do obliczeń czasu, ile procedura zajmuje, to sprawa jest z jednej strony prosta, z drugiej bardziej jednak złożona i wymagająca uczynienia pewnych uwag.

    Ponieważ startujemy z VCONT $D40B = 0, to odczyt z tego rejestru na koniec wiele nam sam w sobie już może powiedzieć (ale pod emulatorem rozsądniej jest posłużyć się odczytem linii kreślonego w tym momencie obrazu, który jest precyzyjniejszą dwakroć formą rejestru VCOUNT). Dodatkowo wersja wyjściowa robi niemal dokładnie pełen przebieg 1 ramki (to jej czas). Więc odczyt linii obrazu (+1, bo licznik bije od 0 do 311) i podział tego przez 312 (lub 156 jeśli odczytujemy z VCOUNT), daje nam rozsądną precyzję uzyskanej informacji, ile czasu zajmuje dana procedura w odniesieniu do wyjściowej (to te wyliczane % przyspieszenia), a o której wiemy, że działa szybciej od wyjściowej, bo poniżej 1 ramki. To jest ta prosta strona tego obliczania czasu. (Gdyby to nie było jasne, czy podmieniona procedura właściwa do wyłaniania bitu z bajtu jest istotnie szybsza i mieści się w ramce, to trzeba to sprawdzić przez odczyt na początek i na koniec, zawartości licznika "na ramce", $14, czy przypadkiem nie jest większa wartość odczytu drugiego od pierwszego o więcej niż 1; licznik $14 nabija nie z końcem dojścia do wartości licznika obrazu 311 i zmiany na 0, ale gdzieś chyba między 255 a 256, co też trzeba czasem uwzględniać.)

    Obliczanie tak czasu wykonywania i porównywanie wydzielnych i podmienianych procedur między sobą, trzeba jednak uznać za mocno szacunkowe i zgrubne.

    A oto tego główny powód:
    Porównywany jest czas wykonywania całego programu (z obsługą i wyświetlaniem), a więc nie tylko ten przeznaczany do wyspecjalizowanego zadania (wyciągania bitu z bajtu). W efekcie różnica czasu w działaniu porównywanych procedur jest (istotnie) spłaszczana. Więc realna różnica efektywności jest w rzeczywistości wyższa niż wyniki tych zgrubnych obliczeń.
    • 20: CommentAuthormarok
    • CommentTime27 Dec 2022
     
    Bardziej finezyjna wersja. To jest ta wersja szybsza o +~10% (ten mało szczęśliwy zapis oznacza, że jest to więcej niż 10% ale być może mniej już nawet niż 11% - przy tej uproszczonej metodzie szacowania, o której dużo napisałem).

    par1    asl @
    parS asl @
    beq ret
    dta {beq}
    par2 asl @
    bcc par2
    bmi par1
    beq ret
    asl @
    eor #$80
    bne par2
    ret rts


    Pierwotnie była to wersja z tymi (poniżej) linijkami kodu (bezpośrednio) przed "ret rts", zamiast tych trzech, które są teraz.
    Wiąże się to także z tym, że rozkaz "clc" dodałem na końcu, aby to zaczęło działać poprawnie (wstępnie nie objąłem tego w logicznym przewidywaniu że bez tego dodatkowego rozkazu nie będzie; dodam do tego iż potem pierwsze próby "zachachmancenia" aby się tej istrukcji sprytnie może jakoś pozbyć nie przyniosły rezultatu). Piszę o tym w detalach, bo jeszcze kilka wypełniających historię podejścia do problemu zamierzam zdradzić, więc chciałbym aby to stanowiło pełen obraz, i może trochę w celach szeroko rozumianej "dydatkyki" (dla potencjalnych początkujących w kodowaniu, zwłaszcza w 6502).

    eor #$40
    bne par2
    clc


    Troszkę się o tej wersji wypowiem dla czytelności i w poparciu dla jej istnienia.

    Poza tym, że jest szybsza, nie angażuje jeszcze rejestru X. Nie zlicza bitów (ustawionych), ale je "paruje" na wyjściu (służą temu znaczniki C i N). Jeśli bit niesparowany ucieka poza bajt to wraca do bajtu ale "ergonomicznie" (aby np. nie kręcić się w kółko z nim w bajcie, co by nie miało żadnego sensu). Duże użycie skoków warunkowych nie sprawia, że procedura jest wolna (warto zauważyć; intuicja tego nie podpowiada).
    Spryt polega głównie na "nowocześniejszym" (bardziej ergonomicznym) podejściu do eliminacji bitów ustawionych z bajtu w procesie ich wysuwania i krótszej pętli podstawowej (tylko na 5 cykli gdy obracamy "powietrzem" - uzyskujemy na wyjściu bity zgaszone). Ponieważ na wysuwaniu z bajtu również (jak wersja poprzednia) opiera się ta wersja także. Wspólne jest także baczenie czy przypadkiem nie można całego procesu już przerwać (jest to wręcz konieczne, aby procedura sama się nie zapętliła w nieskończoności), bo bajt (w procesie sprawdzania jego zawartości) jest już pusty.

    Ogólnie, to raczej pasuje mi taki styl tworzenia kodu (sprawia satysfakcję).

    Natomiast piszę o tym w ten sposób i dokładnie może tak a nie inaczej, bo to nie koniec prezentowanych wersji. Mam jeszcze jedną do zaprezentowania (i omówienia).


    Ta ostatnia jest obiektywnie najlepsza. Decydują o tym łacznie dwa czynniki. Jest najszybsza ogólnie (w marginesie pewnych wartości bywa wolniejsza). Jest doskonale stabilna czasowo (działa z tą samą prędkością dla każdej wartości).
    Więc jeśli sumarycznie dla wszystkich wartości procedura działa najszybciej, a działa z tą samą prędkością wykonywania zawsze, to jest to wskazanie bezwględne na korzyść tej procedury, bo to są jedyne cechy wydajnościowe, jakie mogą być brane pod uwagę (obie świadczą na plus).

    Procedura jest wg schematu obliczeń, którym się tutaj posługuję, o ~25% szybsza od wersji pierwszej (wyjściowej).

    reg equ $ff
    parS sta reg
    :4 asl @
    eor reg
    sta reg
    :2 asl @
    eor reg
    sta reg
    asl @
    eor reg
    asl @
    rts


    Jak widać, na pierwszy rzut oka jest to "kod rozpisany" (nie ma pętli). Angażuje pomocniczo (co jest pewnym obiektywnie mankamentem) bajt z pamięci strony zerowej (aby było to szybkie). Bajty z tej strony pamięci można traktować z dużym przybliżeniem jak dodatkowe rejestry (registers), których 6502 ma niewiele (a między tymi które ma nie ma takich operacji jakie ma rejestr akumulatora z pamięcią; np. "eor x"). Mimo wszystko mnie osobiście to nie przekonuje pod względem estetycznym do tworzenia takiego kodu (osobiście unikam).
    Rozwiązanie tego rodzaju można nazwać ogólnie banalnym, bo na rozpisaniu kodu poza pętle polegają optymalizacje czasowe w różnych sytuacjach, kiedy na szybkości wykonywania kodu szczególnie komuś zależy. Jest to (złoty?) standard, chociaż w rodzaju "brutal force" (bo nie ma tu finezji, inaczej: śladu poradzenia sobie z problemem jakimś niestandardowym logicznym podejściem).
    Mimo to, ta konkretna procedura ma pewien rys pomysłowości, bo sama możliwość zastosowanie tej metody do rozwiązania tego zadania nie nasuwa się od razu (raczej może być odrzucona jako nie do zastosowania). Więc spryt jaki się kryje w tej procedurze polega na, w pierwszej kolejności, że bity można eor-ować wewnątrz bajtu między sobą wzajemnie po przesunięciu (otrzymując tak wyniki cząstkowe). Bity się "składają" do coraz mniejszych obszarów bajtu (8,4,2,1). Drugie spostrzeżenie wcale nie takie oczywiste jest takie, że nie trzeba się przejmować pozostałą zawartością bajta podczas tego procesu składania bitów.



    W podsumowaniu - tło historyczne, jak do tego doszło, że powstał ten wątek.

    Paradoksalnie, zaczęło się od ogólnego pomysłu "na składanie bitów" w bajcie (w zamyśle dla możliwości uzyskania bitu parity). Zaświtała mi taka idea w dwóch wersjach. Najpierw ta "symetryczna" (8->4->2->1), ale zaraz też obok z przesuwaniem zawartości tylko o 1 bit, czyli nadal przy operacjach na zawartości tego samego rejestru (czy tak też można i czy może to być sposób, bo "symetryczna" wydawała się zbyt czasochłonna, a przyszło jeszcze na myśl, że konieczne może się okazać przesłanianie części bitów w całym procesie). Była to idea ogólna (czysto w myślach, nie przekładana "na kartkę").
    Z tym bitem parity w ogóle to było nie z potrzeby, ale zaświtało czytając o procesorze, który go posiada, i chwilkę na to poświęciłem aby się zastanowić, jak wyprowadzić ten bit z bajtu (jeśli nie robi tego sam procesor). To wtedy pojawiła się ta idea "składania", czy przypadkiem nie da to prawidłowego rezultatu (trochę kusiło spróbować).
    Było już późno i cała akcja, jak na moje standardy, potoczyła się błyskawicznie. Mając chęć zacząłem coś klecić z przesuwaniem o 1 bit (nie rozpatrywałem "symetrycznej" wersji), ale szybko spostrzegłem, że coś mi to nie idzie (nie mam tego dopracowanego koncepcyjnie i napotykałem trudności) i zmierza trochę w innym kierunku. Kombinowałem trochę w tym momencie bez skutku. Niedługo potem pomyślałem, że jednak pewnie ten standardowy pomysł, jaki się narzuca (a mi wychodzi z prób, że efektywnie tak to wypada tylko zrobić), aby wykonać to zadanie (zliczania bitów zapalonych) może okazać się raz że najwydajniejszy, dwa że najkrótszy (przyzwoitej długości jak na nieskomplikowane zadanie). Więc powstała najpier wersja "wyjściowa" (z pierwszego publikowanego tutaj kodu) i przybrała ona dla mnie zachęcającą postać (nie znięchęciła do tematu), ale trochę próbując to i owo przy niej i nie zadawalając się do końca nią (choć wydawało mi się to z początku prawdopodobnie sprawą przegraną) doszło do wyłonienia wersji drugiej z opublikowanych (jeszcze z błędem, bo bez "clc"). Stało się to w miarę szybko i w zasadzie niespodziewanie. Dopisałem krótką obsługę wyświetlania i zaraz odpisałem emulator aby sprawdzić czy to działa. Po poprawieniu banalnych błędów formalnych w zapisie źródła, które uniemożliwiały asemblację, a którym prawie zawsze nie umiem zapobiec, odpaliłem i oczom moim - nieprzygotowanemu, jak się okazało - ukazał się widok z drugiego obrazka (na szerokim ekranie). Miałem już pewność, że coś zdołałem schrzanić w tak oczywistym programie, który nie można było schrzanić (ale ja zawsze potrafię), więc zaraz zacząłem "debugować". No ale, raczej wszystko wyglądało poprawnie, jeśli chodzi o logikę działania, więc zacząłem dopiero teraz rozpatrywać, czy ten obraz faktycznie nie jest prawidłowy? Wydawał się taki dziwny, jakby mało schematyczny, nieprzekonujący.

    Dlatego (poza pewną kokieterią, którą zwykłem stosować) w pierwszym wpisie napisałem, że "sam bym nie rozpoznał" tego ekranu, bo faktycznie tak było. Mimo że pisałem już bardziej o obrazie na zawążonym ekranie, który robi znacznie lepsze wrażenie. (Nie wiem jakbym zareogował na ten drugi obraz, może lepiej.)

    Później sprawdziłem tą drugą wersję. Zauważyłem błąd w działaniu (był inny obraz), lekki debug i "złapanie" gdzie leży tego przyczyna. Szybka riposta w postaci dodania nowej linii kodu z "clc".

    Zaraz potem, kiedy już to ogarnąłem, stwierdziłem, że w sumie to jest fajny chyba temat na forum, aby się z tym obrazem z parity bit pokazać. Wpadł pomysł na quiz.

    Nie miałem dużych wahań, po prostu to zrobiłem.

    Wersja najnowsza powstała wczoraj z samego rana (czasem rozważam krótki kod w myślach i bywa że to wtedy coś "zaskoczy"). Wersja druga bez "clc" chyba na trzeci dzień po pierwszym (w tych samych okolicznościach).

    Jeśli się za bardzo chwaliłem skromnymi dokonaniami, to przepraszam za nieprzyjemności.

    Może się teraz zdarzyć, że wszystko to już było i ktoś to dawno już napisał (w takiej a może doskonalszej formie), a to jest wręcz na widoku (specjalnie dedykowane do zapoznania się z tym). Przyznaję, że nie sprawdzałem, ale możemy się niedługo znaleźć (a może już tu jesteśmy), że każdy problem z dziedziny względnie podstawowej ma swoje opracowanie wzorcowe (na dany procesor), do którego istnieje łatwy dostęp. W sumie to podchodzenie do problemów na zasadzie najpier to sprawdzę czy tego nie ma, jest dobre z różnych perspektyw, ale na pewno nie pozwala samodzielnie zmierzyć się z danym problemem.
    • 21:
       
      CommentAuthorsun
    • CommentTime27 Dec 2022
     
    na sąsiednim forum masz też ten temat pociągnięty, ciekawe procki wraz z tabelą wyników prędkości ->link<-
    • 22: CommentAuthoratariki50
    • CommentTime27 Dec 2022
     
    Mogę po całości?

    Mrówki łażą po ekranie.
    • 23: CommentAuthoratariki50
    • CommentTime27 Dec 2022
     
    Masz 8 mrówek.
    Mrówki 1 i 3 zamieniły się miejscami.
    Gdzie jest Mrówka nr8 ?
    • 24: CommentAuthormarok
    • CommentTime27 Dec 2022
     
    @sun: Dziękuję. Nie pomyślałbym że się ktoś zainteresuje, poza tym miejscem.

    Na razie prawie nic nie zrozumiałem z tego, co tam jest, ale to trochę objaw lekkiego szoku i postaram się to nadrobić. (Nie wykluczam wszak trudności.)

    @atariki50: Jeśli miałbym odpowiedzieć najlepiej jak potrafię, to:
    Mrówka nr8 jest tam, gdzie była przez zamianą miejscami 1 i 3. Ale gdzieś ją tam postawił, to brakuje mi podpowiedzi, która w tym wypadku wydaje się konieczna.
    • 25: CommentAuthormarok
    • CommentTime27 Dec 2022
     
    @sun: Wersja Willego (ta część parity8) jest identyczna z tą ostatnią (najszybszą), którą podałem.
    • 26: CommentAuthoratariki50
    • CommentTime27 Dec 2022
     
    @marok
    Jeśli test jest częścią jakiegoś większego projektu,planu czegokolwiek.
    To Ok.
    Jeśli nie to mrówka nr8 nie musi zachować swojej pozycji.
    Tu nie ma pułapki:)
    Zmiana wartości mrówek 1,3 definiuje pozycję mrówki 8 ale na pozycji np.5 .

    Wracając do tematu. Da się to wykorzystać do pisania gier lub programów?

    Bo wygląda ciekawie.
    • 27: CommentAuthormarok
    • CommentTime27 Dec 2022
     
    @atariki50: Nie widzę tego (by się dało).

    Jest potencjalnie tylko jedno zastosowanie, ale mocno dyskusyjne (i co więcej - zrealizowane).

    Ten bit nawet jeśli jest w jakimś procku obecny (8086, Z80), a załóżmy że chcemy pracę takiego procka symulować innym (naszym), aby na przykład gra (czy program) z tego innego procka działała w "stanie surowym" (napisana pod inny procek, nie po przeróbce) w takim pieczołowicie uczynionym dla nas emulatorze (działającym na Atari!), to czy nawet wtedy ten bit jest w praktyce wykorzystywany przez tę grę? Możliwe właśnie, że wcale nie jest(!), bo praktyczna przydatność tego bitu nawet dla procesora, który jest w niego wyposażony, jest w zasadzie żadna, z tego co mi się przynajmniej wydaje. Nie jestem pewien czy są instrukcje, które kooperują jakoś z tym bitem. Jak teraz trochę podczytuję o 8086 to jest tego bardzo niewiele (może nie doczytałem dobrze; coś oczywiście być musi, ale w praktyce okazuje się to niewykorzystywane w zdecydowanej większości programów), a jak to wygląda w Z80 to nie wiem, ale poprzez analogię (nie są to procki od siebie dalekie) nie sądzę by była tu jakaś większa różnica.

    Wiesz zapewne, że jest emulator ZX80 na Rapidusa (65816). Nie miałem okazji widzieć go w akcji nawet na emulatorze, a tym bardziej jakoś podejrzeć, co się tam może dziać "w środku" (programu emulatora), ale osobiście wyobrażałbym sobie, że emulacja tego bitu nie musiała nawet zostać przeprowadzona. Jest przynajmniej dla mnie taka opcja, niemniej jest to mniej prawdopodobne niż że jednak jest to zrobione (z całą dokładnością; przyszło mi jeszcze na myśl, że może jest to jakoś okrojone do sytuacji tych kilku szczególnych instrukcji, jak przesyłanie do rejestru akumulatora zawartości rejestru znaczników). Przyjmując jednak że jest, to jest tam jakaś inna wersja tego wykorzytana. Jak to się tam ten bit ustala (i czy) to nie wiadomo mi, ale trzeba pamiętać, że tamtejszy kod pisany już jest pod 65816, a ten repertuar instrukcji ma poszerzony i być może łatwiej jest to zadanie osiągnąć za pomocą specyficznych dla tego procesora instrukcji.
    Ale skoro już to jest, to więcej tego już nie trzeba, nigdzie. Zastosowanie jedyne jakie sobie wyobrażam, zostało już wypełnione.


    Jeśli test jest częścią jakiegoś większego projektu,planu czegokolwiek.
    To Ok.
    Jeśli nie to mrówka nr8 nie musi zachować swojej pozycji.
    Tu nie ma pułapki:)
    Zmiana wartości mrówek 1,3 definiuje pozycję mrówki 8 ale na pozycji np.5 .


    Nie jest - więc wychodzi na to, że łamigłówka o mrówkach nadal jest w grze (i pytania na jej temat).

    Ostatnie zdanie coś podpowiada, ale nie do końca (zdaje się dozować informacje tak aby przypadkiem nie dało się z tego znaleźć rozwiązania). Nie do końca - nie można, bo to wbrew regułom. Jeśli chcesz jednoznaczne rozwiązanie musisz poinformować o wszystkim co niezbędne by to rozwiązać. Jeśli tego zaniechasz, to jest to wyjście poza reguły (i niedorzeczność). Oczywiście sam decydujesz jakie informacje wg Ciebie są niezbędne do rozwiązania zadania, ale bierzesz za to także sam odpowiedzialność. (Najwyżej będziesz sam świecił oczami przed innymi.) Widzisz, zamieniliśmy się rolami.

    Wciąż jednak wydaje mi się, że prawidłowo sformułowałem swój quiz, bo dostarczyłem wystarczającą ilość potrzebnych informacji, aby to spróbować rozwiązać. Mnie się raczej wydaje, że zabrakło tym razem odrobinę szczęścia i wytrwałości tym (nielicznym), którzy coś tam próbowali.
    • 28: CommentAuthormarok
    • CommentTime28 Dec 2022
     
    W uzupełnieniu.


    (Aktualnie wszystko już się roztrzygnęło. Willy był najsprawniejszy w wyszukaniu metody i opracował to bez zarzutu, że nie było lepszych - choć informacja o tym poszła w innym miejscu, niż to forum. "Gratulujemy!")


    W uzupełnieniu chciałbym jeszcze opisać dwie inne procedurki robiące to, do czego znaleźliśmy już rozwiązanie "optymalne". (Niedowierzam, że znajdzie się jeszcze coś lepszego.)

    Pisałem o wyjściowej wersji (tej mojej pierwszej stąd), że jest intuicyjna.

    Otóż jeszcze bardziej intuicyjna jest inna wersja (można na nią wpaść podobnie szybko a może szybciej, niż na wersję przypominającą wyjściową). Jest także z tych bardzo krótkich i "czytelna" (błyskawicznie można połapać się w tym na jakiej zasadzie działa i się z tym zgodzić). Intuicyjnie nie daje się jednak chyba przewidzieć, że będzie odstawać od reszty tak wyraźnie pod względem tego ile czasu się wykonuje (to + ~20% wolniej niż procedura wyjściowa, przyjmując tamten czas za równy 1 ramce).

    reg equ $ff
    parS sta reg
    lda #0
    par1 eor reg
    asl reg
    bne par1
    asl @
    rts


    Dla pełnej jasności, procedura kolejno eor-uje bity (interesuje nas tylko pozycja najstarszego bitu) ze sobą od najstarszego ku najmłodszemu w bajcie (ale może to przerwać wcześniej o ile nadarzy się okazja, bo bajt się opróżni wcześniej z bitów ustawionych). W tym celu przesuwa oryginalną zawartość bajta zapisaną w pomocniczej komórce pamięci (niestety sama ta jedna instrukcja, powtarzana do 8 razy, zajmuje 5 cykli).


    Zaprzeczeniem dla mnie intuicji jest procedura następna, nie powstała przy moim udziale, a którą powziąłem od Sebana (z innego forum). Długo się na nią wpatrywałem, a trudno mi było zrozumieć pewną egzotyczną dla mnie kombinację instrukcji (jak na realizowane zadanie). Jest dla mnie bardzo oryginalna i godna wyróżnienia w kontekście tego, że wykonuje się szybciej(!) niż wersja wyjściowa (chociaż są to wartości porównywalne) i jest przy tym rozsądnie krótka.

    Od razu zaznaczę, że ta konkretna postać jest nieco przystosowana do delikatnie wydajniejszego działania, bo publikacja wersji Sebana skupiła się głównie na przedstawieniu tej oryginalnej metody a nie "dopiłowywaniu" procedury w cyklach.
    Miałem na tyle dużo czasu, żeby się tym zająć osobiście, co też uczyniłem (sądzę że ze zrozumieniem się to spotka). Procedura działa do (wyjaśniam niżej skąd to "do") ~ 2% szybciej od 1 ramki.


    subvar10 equ 0
    v equ $ff
    parS
    parity cmp #0
    beq endp
    IFT subvar10>1
    bpl plus
    sbc #$80
    beq endp+1
    dta {ldx #}
    EIF

    plus dta {ldx #} ; #0
    inx

    ploop inx
    sta v
    sbc #1

    and v
    bne ploop

    txa
    endp lsr @
    rts


    Omawiając ten kod na wstępie wyjaśniam, że deklaracja subvar10>1 generuje dodatkowe linie kodu, które jeszcze delikatniej (na pograniczu chyba jakiegokolwiek uzasadnienia by to stosować) podnoszą wydajność ogólną kodu. Także dla części wartości wyjściowych może się to okazać przeciwskuteczne (obniżyć wydajność, choć to tylko powinno być 3 cykle na wykonanie istrukcji "bpl plus" ).

    Algorytm opiera się z grubsza na przejściach przez wartości graniczne. Wartością graniczną nazywam tu wartość 2^n (gdzie n jest numerem pozycji najstarszego ustawionego w bajcie bitu).
    Obrazowo:
    z %1(0..) na %0(1..) ( ".." oznacza nieokreśloną ilość powtórzeń wartości bitu).

    Te wartości są przy instrukcji "and v" konfrontowane ze sobą i tak wykrywany jest moment przejścia przez wartość graniczną. Przejście przez wartość graniczną oznacza zaś, że mamy dokładnie jeszcze 2^n (a więc parzystą liczbę powtórzeń, które jako liczba parzysta, nie trzeba już wykonywać, bo nic w sprawie parzystości się już nie zmieni od stanu, który już określiliśmy, znaczy, czy jest to liczba parzysta czy przeciwnie).

    (Niedokładność powyższego opisu polega na tym, że liczba zaniechanych powtórzeń w pętli to jest bardziej liczba 2^n-1, ale stan parzystości, tak czy inaczej, zatrzymuje się we właściwej pozycji. Stan parzystości jest na bicie 0 rejestru X.)
    • 29: CommentAuthormarok
    • CommentTime28 Dec 2022
     
    Willy zaraportował do innego miejsca ("forum obok") o istnieniu "genialnej" wersji (zamykającej usta co bardziej wyrywnym w ogłaszaniu przedwcześnie "wersji optymalnej") realizującej to zadanie.

    No, w jakiejś mierze to genialne spostrzeżenie, na którym opiera się rozwiązanie z raportowanej wersji, ale też z pewnym zawstydzeniem muszę przyznać, że do samodzielnego odszukania wciąż dostępne (na tym trochę "genialność" polega, że się dostrzega coś co inni pomijają). W tym wględzie biorę pod uwagę spory czas (bo to istotny czynnik ocenny), jaki temu poświęciłem.

    sta  p
    asl
    eor p
    and #b10101010
    adc #b01100110
    and #b10001000
    adc #b01111000


    po dostosowaniu:
    p   equ $ff
    parS sta p
    asl
    eor p
    and #%10101010
    adc #%01100110
    and #%10001000
    adc #%01111000
    rts


    Licząc teraz czas wykonania (od razu widać że to szybkie, oraz że szybciej już nie można się spodziewać) po swojemu (jak dotąd) wyszło mi, że tak, to 168 (wartość 167) linia ekranu z odczytu pod emu (w zaawansowaniu początkowym - 18 cykl na 114).

    Więc 168/312 = 0,538461538461
    to powiedziałbym że w takim razie to ~ 46% czasu ramki szybciej, czyli niż czas referencyjny. Jest to teraz właściwa skala porównawcza (to 46% czasu ramki).

    Czyli rozwiązanie referencyjne (wyjściowe), jakby tego nie nazywać, jest nieco więcej niż 2 razy wolniejsze od tego "celującego". (Przy znacznej już niedokładności tego szacunku, niedoszacowaniu tej różnicy, jako że czynnik "spłaszczania" nabiera tu coraz poważniejszej roli. Tak mi się przynajmniej na logikę wydaje.)

    Inni mogą te procedury porównać zdecydowanie precyzyjniej pod względem szybkości ich wykonywania.
    • 30:
       
      CommentAuthorCOR/ira4
    • CommentTime29 Dec 2022
     
    grafika z postu nr1. oprócz oczywistych wymienionych skojarzeń typu szachownica, kojarzy mi się z iluzjami optycznymi.
    • 31: CommentAuthormarok
    • CommentTime31 Dec 2022
     
    Opis metody z poprzedniego wpisu jest zwyczajnie błędny i mylący.
    Pisałem, że procedurę metody adoptowałem, w znaczeniu, że nie byłem jej autorem. W takich sytuacjach może się również zdarzyć, że "poprawiając" kod w rozumieniu podnoszenia jego wydajności lub skracaniu, nie dysponujemy pełnym zrozumieniem jego działania. Są to bowiem zabiegi "techniczne" i tak warto na to spoglądać. Oczywiście w większości wypadków ma prawo mieć to miejsce wokół złożonych i skąplikowanych działań (algorytmów). Ten przypadek jest o tyle szczególny że dotyczy bardzo niedługiego kodu (ergo, nie powinno się to zdarzyć, a tym bardziej kiedy się ktoś bierze za jego omawianie).

    Poczynając w opisie od "wartości granicznej" i później całej reszty, opis jest jawnie mylący.

    Postaram się teraz dokonać "rekapitalizacji" poprzedniej próby.


    Procedura gasi ustawione bity w pętli po jednym (od najmłodszego). To jest w zasadzie wszystko.

    Natomiast gdy ktoś lubi rozwlekle opisywać rzeczywistość, mimo że ta tego generalnie nie wymaga, jak ja, to otwarty jest na bardziej drobiazgowe uszczegółowienia.

    Można więc napisać że, najmłodszy w bajcie z ustawionych bitów jest z "pierwszą" (w pętli) instrukcją (sbc #) "rozkładany", a druga instrukcja (and v) służy zachowaniu pamięci o pozycji rozłożonego bitu i eliminuje "produkt rozłożenia" tego bitu. Kolejna instrukcja (sta v) już tylko trwale zapamiętuje to i przesyła tam, gdzie tego właściwe miejsce. Jest to wartość waloryzowana w pętli, która decyduje o liczbie przebiegów pętli. Wyjściowo, jest to ta sama wartość początkowa z wejścia do procedury (traktowana wybitnie "bitowo"), która zachowuje z czasem coraz mniej bitów swojej pierwotnej wartości (na koniec staje się =0).
    Obliczany tym sposóbem bit parzystości znajduje się na najmłodszym bicie rejstru X, gdyż pętle nalicza liczbę swoich przebiegów poprzez ten rejestr.

    "Rozłożenie bitu" polega na tym, że jest kasowany, a wszystkie młodsze bitu (na prawo) są z kolei ustawiane. Te ustawione bity (dot. tych na prawo) są tym "produktem rozłożenia".

    Rozłożenie bitu i produkt tego rozłożenia można by zilustrować, jak poprzenio to uczyniłem dla "przejścia przez wartość graniczną", czyli:

    z 1(0..) do 0(1..), czyli z - rozkładany bit, do - produkt rozłożenia

    Wyszedł ten opis jak wyszedł (nie mam złudzeń odnośnie jego czytelności), ale trudno. Rzecz, która była z mojej perpektywy do zrobienia.

    Mam jeszcze przygotowaną poprawioną wersję tej procedury. W takiej wersji wykonuje się ~4,5% szybciej niż czas ramki. Wypada więc całkiem nieźle (zależnie z czym przyrównywać).


    v   equ $ff
    parS
    parity
    tax
    lsr @
    beq endp+2
    sec

    ploop inx
    sta v
    sbc #1

    and v
    bne ploop

    endp txa
    lsr @
    rts


    Dodatkowa "optymalizacja" łaczy się z faktem, że używamy "tax" (przyjmowana parzystość na starcie zależy od stanu bity 0 wartości wyjściowej) i mamy szansę (1/2) na jedną interakcję pętli mniej ("lsr").


    Zapowiem jeszcze że, do tej "genialnej" procedury też się przymierzam jeszcze odnieść, w podobnym stylu.
    • 32: CommentAuthormarok
    • CommentTime31 Dec 2022
     
    @ IRATA4: Może, faktycznie, nie jest to złe skojarzenie.
    • 33: CommentAuthormarok
    • CommentTime2 Jan 2023
     
    Muszę (czy powinienem) się wyplątać z podawanych nieprawd (do atariki50), bo doczytałem wreszcie o instrukcjach skoków warunkowych od stanu bitu parity - że są, bo wydawało mi się, że ich brakuje, i na tej podstawie formułowałem pewne myśli i sądy (dotyczące choćby emulacji Z80 przez słynny emulator ZX na Atari autorstwa Draco).

    Więc ten bit flagi procesora, mimo że niekonienicznie specjalnie użyteczny w realnym konstruowaniu algorytmu kodu (taka opinia zdaje się jest uprawniona), jest pełnoprawnym "uczestnikiem" "życia procesora".

    Gdyby bowiem tych skoków nie było (tłumaczę błąd wcześniejszego rozumowania), to ustalanie tego bitu mogłoby być w jakimś stopniu rzeczą pomijalną w emulacji lub (choćby) opcjonalną, czy uruchamianą dla niektórych instrukcji - odwołujących się do rejestru flag. Sądziłem właśnie tak, także z tego powodu, że nie uwzględniłem w swoich rozważaniach tak doskonale zoptymalizowanej formy procedury wyciągającej bit parity z wartości, o której dziś wiem(-y). Jej istnienie powoduje, że nie jest to proces uciążliwy, a więc nic nie stoi na przeszkodzie by go włączyć do rutynowych działań emulujących stan rejestrów procesora (w tym wypadku rej. flag).

    Uwzględniając teraz "formę ostateczną" procedury uzyskującej bit parity (mowa o tej "doskonale zoptymalizowanej"), nie było też na miejscu wspominanie o "większym repertuarze rozkazów w 65816" w kontekście może lepszej konstrukcji takiej procedury ze względu na przewagę w możliwości doboru specyficznych dla tego procesora istrukcji. Z uwzględnieniem tego, co teraz jest mi wiadome, nie wydaje się to w żaden sposób pomocne (wcześniej i tak tylko czysto ogólnie teoretyzowałem na ten temat, a nie pisałem nic konkretnie, mimo tego - błędnie i nieroztropnie).