Wskazówki do gry w golfa w DC

18

Jakie masz ogólne wskazówki na temat gry w golfa w DC ?

dc to narzędzie do kalkulacji dla systemu UNIX / Linux, które poprzedza język C. Jestem zainteresowany tym, jak skrócić moje programy DC (obliczenia?). Szukam pomysłów, które można zastosować do ogólnego które są co najmniej trochę specyficzne dla dc (np. Usunięcie komentarzy nie jest pomocną odpowiedzią)

Proszę zamieścić jedną wskazówkę na odpowiedź.

mriklojn
źródło
7
Zamiast tego użyj Marvela.
Magic Octopus Urn

Odpowiedzi:

6

Instrukcje if-then-else

Załóżmy, że chcemy sprawdzić warunek a==b(pozwolić ai bbyć przechowywany w odpowiednio nazwanych rejestrach).

edytować:
[         # Everything is wrapped in one big macro
  [         # An inner macro for our *then* part
              # <-- Stuff to execute if a==b here
  2Q          # Then quit the inner and outer macro
]sE       # `E' is for Execution register ;)
la lb =E  # if a==b, execute E
          # if E is executed, it will quit the whole macro, so the rest is never reached:
          # <-- Stuff to execute if a!=b here
]x        # End macro; Execute

Niech (foo)będzie symbolem zastępczym w celu kondensacji:

[[(then)2Q]sE(condition)E(else)]x

Jest całkiem pewny, że jest to najbardziej zwarta instrukcja if (dostępna również tutaj ).

Joe
źródło
1
Może [[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI fto początek? Akcje dla tehn i innych są na stosie, Imakro „ f” zamienia je i jest warunkowo caled. wtedy górna część stosu zostanie wykonana, a nieużywane makro zostanie umieszczone w I, aby wyczyścić stos. 2 4są tylko przykładowymi danymi do porównania. Alternatywnie, [x]sIczęść może zostać przeniesiony do porównania, jeśli uważane za bardziej czytelne: [[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f. W fprzykładach po prostu pokaże, że stos jest potem czysty ...
1
Strona Rosetta Kodu o Dc wymienia 3 smaki dci to była strona 1-ty gdzie widziałem OpenBSD dcjest if-then-elsekonstrukt. Myślę, że potrzebujemy dcpakietu wentylatora ze wszystkimi 3 wersjami dla wszystkich głównych systemów operacyjnych ... o :-) ... a moja if-then-elsepowyższa propozycja nie działa na oryginale, dcponieważ brakuje mu rpolecenia ... :-(
1
Co powiesz na: [[(if)2Q]si(condition)i(else)]x - zawinięciem całej rzeczy w makro, a częścią if wewnątrz innego makra wewnątrz tego, abyś mógł 2Qwydostać się z całości przed dotarciem do części else. Więc jeśli chcesz zrobić, jeśli 1 == 1, a następnie wydrukuj 1, a następnie wydrukuj 2 , byłoby to 1[[1P2Q]si1=i2P]x(niesprawdzone, ponieważ nie mam dostępu do dc tu i teraz. Byłem również pewien, że zrobiłem tę sztuczkę w odpowiedzi tutaj wcześniej ale nie mogłem go znaleźć)
daniero
Tak, zrobiłem matematykę, moja sugestia jest krótsza. Z tego samego przykładu, „zapis” i usuwanie odstępy to [/*else*/]sE[[/*then*/]sE]sIlalb=IlExvs [[/*then*/2Q]sIlalb=I/*else*/]x- 6 bajtów różnicy. Wciąż nieprzetestowane: P
daniero
1
Dobra robota, @daniero! Zaktualizuję post, kiedy będę miał czas, lub możesz to zrobić, jeśli chcesz.
Joe
5

Możesz zapisać dane wejściowe za pomocą d

Używając d, który powiela ToS (góra stosu), możesz przesunąć wejście z drogi do późniejszego użycia, wciąż będąc w stanie z niego korzystać.

Rɪᴋᴇʀ
źródło
@NoOneIsHere oh cool !!! Dzięki!
Rɪᴋᴇʀ
5

Tablice

Chociaż są to bóle głowy dla początkujących, dcoferuje tablice. Działają w ten sposób:

value index :a    # store `value' in array linked to top of stack `a', with index `index'
      index ;a    # push a[index] on (main) stack

Jak zwykle pierwszy element ma indeks 0. Tablice mogą być przydatne podczas pracy z sekwencjami, jak w sekwencji SUDSI , szczególnie w połączeniu z licznikami. Tablice mogą zmniejszyć ilość przetasowań liczbowych, które musisz wykonać (oraz liczbę liczników i porównań), jeśli chcesz wybrać konkretny element bez niszczenia środowiska. Na przykład, jeśli chcesz przenieść stos liczb do tablicy, możesz napisać funkcję rekurencyjną, która używa z(głębokość stosu) lub z 1-jako indeks, przechowuje element i sprawdza, czy z == 0sam się zakończy.

[z 1- :a z 0 !=F]dsFx    # or I could just write such a function for you :)

Pamiętaj o następujących kwestiach:

  • Tablice są powiązane z instancjami na nazwanych stosach. Jeśli wypchniesz nową wartość na stos, z którym jest powiązana tablica, tablica ta również zostanie „wypchnięta”, a „nowa” tablica zajmie jej miejsce. Stara tablica nie będzie użyteczna, dopóki odpowiednia wartość na nazwanym stosie nie będzie również użyteczna (tj. Na szczycie stosu). To skomplikowana koncepcja, którą lepiej wyjaśnić dobrą animacją, która jest poza mną.
  • Ty można przechowywać rzeczy w nazwie tablicy bez faktycznie przesuwając wartości do odpowiedniego rejestru nazwie. Jednak jeśli to zrobisz, ty mieć dostępu do stosu / rejestru o tej nazwie przez resztę sesji. dcrozbije się.
  • Jeśli usuniesz wartość z nazwanego stosu, wszystkie wartości w odpowiedniej tablicy zostaną utracone - bez ostrzeżeń, bez zabezpieczeń, bez niczego. Właśnie zniknął (co może być również przydatne).
Joe
źródło
Dobra robota z poradami DC!
Rɪᴋᴇʀ
dcmogły zostać niedawno zaktualizowane, a zachowanie tablicy mogło ulec nieznacznej zmianie w związku z awarią. Nie mogę tego teraz potwierdzić, ale myślę, że ostatnio było inaczej w Linuksie.
Joe
1
Jeśli spróbujesz odczytać indeks z tablicy, która nie została ustawiona, otrzymasz 0, a nie błąd. Co może być bardzo przydatne, ale warto również pamiętać, jeśli potencjalnie wstawiasz zera do tablic ... Będziesz potrzebować innego sposobu na sprawdzenie, czy indeks został dotknięty.
brhfl
5

0 do n-tej potęgi zamiast warunków / makr

Czasami trzeba coś podobnego trójargumentowy warunkowy:

A == B ? C : D;

Dobry sposób na poradzenie sobie z tym jest opisany w odpowiedzi @ Joe . Możemy jednak zrobić lepiej:

0AB-^E*C+

gdzie E to D - C.

Sprawdza to równość, podnosząc 0 do potęgi różnicy dwóch wartości. Daje to 1, jeśli jest równy, a 0 w przeciwnym razie. Reszta po prostu skaluje 1 lub 0 do wartości C lub D. Działa to, ponieważ dcdaje 0 0 = 1 i 0 n = 0 dla n! = 1.

Cyfrowa trauma
źródło
4

Czasami konieczne jest odrzucenie liczby ze stosu. Jednym ze sposobów jest po prostu wstawienie go do nieużywanej zmiennej, tj st. Jednak w niektórych sytuacjach możesz umieścić go w kilku innych miejscach, np. W bazie danych wejściowych, gdy nie masz już danych numerycznych, lub w specyfikatorze dokładności, jeśli nie masz żadnych operacji do wykonania, w których precyzja miałaby znaczenie. W pierwszym przypadku użyj i. W tym drugim przypadku użyj k.

Cyfrowa trauma
źródło
Jeśli wyjście numeryczne nie jest ważne, omożna go również użyć. A jeśli którakolwiek z tych rzeczy jest nieistotna, można ją wykorzystać jako pamięć, a także po prostu odrzucić odpowiednio - I/ K/ Oprzywołać je i zapisać bajty nad sa/ laitd. Prawidłowe wartości AFAIK: i2-16; kdowolna nieujemna liczba całkowita; odowolna liczba całkowita większa niż 1.
brhfl
4

Obliczanie długości: Z, X, iz

Zwyskakuje ToS i wypycha liczbę cyfr (dziesiętną), jeśli jest to liczba lub liczbę znaków, jeśli jest to ciąg znaków. Może to być przydatne do wykrywania długości wyniku (do buforowania danych wyjściowych) lub obliczania długości łańcucha. Pamiętaj, że w przypadku liczbZ przesuwa łączną długość części całkowitej i części ułamkowej.

Xwyskakuje ToS i przesuwa liczbę cyfr w części ułamkowej liczby. Jeśli ToS był ciągiem, 0jest wypychany.

Aby znaleźć liczbę cyfr w części całkowitej liczby, można użyć jednego dZrX-. Jeśli nie zmieniłeś precyzji od domyślnej k==0, użycie 1/Zjest krótsze, ale załóżmy, że musisz zachować określoną niezerową precyzję po operacji: Kr0k1/Zrkto raczej odrażliwość.

zprzesuwa liczbę przedmiotów na stosie. Jedno z moich ulubionych poleceń, w rzeczywistości nie wyświetla żadnych wartości! Można go użyć do wygenerowania sekwencji liczb lub zwiększenia licznika. zdWielokrotne użycie (powiedzmy na początku makra) może pozwolić przetestować obliczenia dla każdej liczby naturalnej lub liczby całkowitej w porządku rosnącym.

Joe
źródło
Używałem ztego i tamtego wcześniej, ale nigdy nie przyszło mi do głowy, aby użyć go jako
hacka
4

Cyfry Ado Fmogą być używane zamiast liczb od 10 do 15. Jednak nadal muszą być one skutecznie traktowane jako cyfry podstawowe 10 (zakładając, że podstawa wejściowa to 10), gdy znajdują się w różnych miejscach. Innymi słowy, przy podstawie wejściowej 10 FFnie będzie reprezentować 255, to będzie reprezentować (15 * 10) + 15lub 165.

W rzeczywistości to działa dla wszystkich cyfr 0, aby Fw dowolnej zasady wprowadzania 2do 16. Więc jeśli podstawa wejściowa to 5, to 26Ebyłoby (2 * 5^2) + (6 * 5) + 14lub 94.

Uwaga: takie zachowanie obowiązuje dla niezmodyfikowanych źródeł GNU. Jednak, jak wskazuje @SophiaLechner, dystrybucje oparte na RedHat wydają się używać bc-1.06-dc_ibase.patch co zmienia to zachowanie, więc cyfry> = ibase są traktowane tak ibase - 1, niezależnie od ich rzeczywistej wartości. Zauważ, że TIO dc wydaje się nie mieć bc-1.06-dc_ibase.patch (mimo że jego Fedora 28 ¯_ (ツ) _ / ¯).

Cyfrowa trauma
źródło
Nie jest to całkiem słuszne - chociaż pojedyncze cyfry powyżej podstawy wejściowej są interpretowane tak, jak można się spodziewać, jeśli literał ma wiele cyfr, a nawet przecinek dziesiętny, niepoprawne cyfry podstawy są interpretowane jako (baza-1). Zatem w wejściu podstawa 10 FFreprezentuje 99, w wejściu podstawa 5 26Ejest taka sama 244, tj. Podstawa 10 74.
Sophia Lechner,
@SophiaLechner Czy jesteś pewien? tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A Z której dcwersji korzystasz? Używam GNU dc 1.4.1 na Ubuntu i GNU dc 1.3 na MacOS
Digital Trauma
Ciekawy. Używam 1.3.95 na Red Hat, a oto twój przykładowy program: [slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep' 99 74 [slechner @ XXX] $ dc --version dc (GNU bc 1.06 .95) 1.3.95
Sophia Lechner
Argh ... nie mogę sprawić, by blok kodu działał w komentarzu. Chodzi o to, że dane FFpwyjściowe 99w 1.3.95. Czy mógłbyś to sprawdzić w swojej wersji MacOS?
Sophia Lechner
1
Jasne! Dziękuję za wszystkie badania.
Sophia Lechner
2

Podczas inicjowania makra funkcji (użyjemy F), które chcesz uruchomić natychmiast, użyj czegoś takiegodsFx zamiast sFlFx. To samo działa dla zmiennych: dsazamiast sala.

Jeśli musisz robić inne rzeczy między przechowywaniem a ładowaniem (np. sa[other stuff]la), Nadal rozważ, czy powyższe jest wykonalne: jeśli pozostawisz wartość na stosie przed innymi operacjami, czy będzie z powrotem na górze do końca tych operacji?

Joe
źródło
2

Właśnie to odkryłem przez przypadek. Jeszcze inny sposób na wygenerowanie zera:_ .

_jest sygnałem dla DC, że następujące cyfry są liczbą ujemną. Przykład:

_3 # pushes -3

Ale co, jeśli nie podążymy za nim z liczbą?

_ # pushes 0...sometimes

Działa to, gdy następny niepusty znak po znaku podkreślenia nie jest cyfrą. Jeśli cyfra następuje po nim, nawet po nowej linii, jest interpretowana jako znak ujemny.

c4 5_6  # -6,5,4
c4 5_ 6 # -6,5,4
c4 5_
6       # -6,5,4 # still a negative sign since the next thing it sees is a digit
c4 5_z  #  3,0,5,4 # if it's followed by a non-digit, it's a 0
c4 5_p6 #  6,0,5,4
c4 _*   #  0 # 4*0=0
Joe
źródło
1

Jeśli zawartość całego stosu wymaga wydrukowania na końcu programu, do osiągnięcia tego można użyć rekurencyjnej pętli makro. Jednak użycie fpolecenia jest znacznie krótsze .

Cyfrowa trauma
źródło
1

dcodczytuje wprowadzanie linii na raz. Jeśli chcesz czytać w wielu elementach, wykonanie tego jeden na wiersz wymaga albo ?odczytu dla każdego wiersza, albo niewygodnej pętli makr. Zamiast tego, jeśli wszystkie elementy wejściowe można umieścić w jednym wierszu oddzielonym spacjami, jeden z ?nich odczyta wszystkie elementy wejściowe, popychając każdy z nich na stos.

Na przykład w seq 10 | dc -e'?f', seqwypisuje liczby całkowite 1-10, po jednej w wierszu. po ?prostu odczyta pierwszy, 1który zostanie fwyrzucony, gdy zrzut całego stosu. Jednak w seq 10 | tr '\n' ' ' | dc -e'?f', trpowoduje, że wejściowe liczby całkowite są oddzielone spacją. W tym przypadku ?będą czytać wszystkie liczby całkowite z linii za jednym razem i fwypiszą je wszystkie.

Cyfrowa trauma
źródło
1

Jeśli operator jest ograniczony ze źródła, utwórz nowy za pomocą a

Coś, co przydało mi się teraz kilka razy, to unikanie używania konkretnego operatora przez przesuwanie wartości ASCII operatora, używanie go ado konwertowania go na ciąg znaków i sprzesyłanie go do rejestru, który zostanie później wykonany jako makro na. Na przykład muszę dokonać podziału, ale jestem albo niedozwolony, albo staram się unikać używania postaci /. Mogę, zamiast zrobić 47asd, a następnie w przyszłości, gdy trzeba podzielić 16 przez 4, 16 4 ldx.

  • Działa to tylko w przypadku operatorów jednoznakowych (nie można zbudować łańcucha) i nie działa w przypadku takich poleceń, sktóre muszą być przez coś naprawione.
  • Dodaje to sporo bajtów i dlatego jest odpowiednie tylko wtedy, gdy unikanie określonej postaci jest konieczne lub w jakiś sposób daje premię do wyniku.
brhfl
źródło
1

Unikanie białych znaków

Unikanie białych znaków pojawia się w kilku wyzwaniach i ogólnie jest łatwe dc. Oprócz ciągów, jeden bardzo specyficzny czas, że konieczne staje się białe znaki podczas pchania jest kilka numerów w jednym rzędzie: 1 2 3. Jeśli należy tego unikać:

  • Wykonać pusty makro pomiędzy: 1[]x2[]x3[]x.
  • Jeżeli wsporniki są ze stołu, przechowywać NOP makra z wyprzedzeniem: 35asni wykonać go w pomiędzy: 1lnx2lnx3lnx.
brhfl
źródło
Możesz także przeciąć oddzielne numery, jeśli chcesz pogodzić się z dc: ',' (054) unimplementedostrzeżeniami.
Digital Trauma
Nie myślałem o tym - przypuszczalnie dotyczy to dowolnego tokena, który nie rozwiązuje polecenia… ciekawe…
brhfl