Tips untuk bermain golf di dc

18

Apa tips umum yang Anda miliki untuk bermain golf di dc ?

dc adalah utilitas kalkulator untuk UNIX / Linux yang ada sebelum bahasa C. Saya tertarik bagaimana cara membuat program dc saya (kalkulasi?) Lebih pendek. Saya mencari ide yang dapat diterapkan pada umum yang setidaknya sedikit spesifik untuk dc (mis. Menghapus komentar bukanlah jawaban yang membantu)

Silakan kirim satu tip per jawaban.

mriklojn
sumber
7
Gunakan Marvel sebagai gantinya.
Magic Octopus Mm

Jawaban:

6

Pernyataan if-then-else

Misalkan kita ingin memeriksa kondisi a==b(biarkan adan bdisimpan dalam register masing-masing bernama).

edit:
[         # 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

Biarkan (foo)menjadi penampung, untuk tujuan kondensasi:

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

Cukup yakin ini adalah pernyataan yang paling ringkas jika memungkinkan (juga ditampilkan di sini ).

Joe
sumber
1
Mungkin [[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI fini awal? Tindakan untuk tehn dan lainnya ada di stack, Imakro "f" menukar mereka dan dikondisikan secara kondisional. maka bagian atas tumpukan akan dieksekusi dan makro yang tidak digunakan akan jatuh di I untuk membersihkan tumpukan. 2 4hanyalah contoh data untuk dibandingkan. Atau yang [x]sIbagian dapat dipindahkan ke perbandingan, jika dianggap lebih mudah dibaca: [[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f. Dalam fcontoh hanya akan menunjukkan tat tumpukan bersih setelah ...
1
Halaman Rosetta Kode tentang Dc menyebutkan 3 rasa dcdan itu halaman 1 di mana saya melihat OpenBSD dc's if-then-elsekonstruk. Saya pikir kita perlu dcbundel penggemar dengan 3 rasa untuk semua sistem operasi utama ... o :-) ... dan if-then-elseproposal saya di atas tidak berfungsi pada aslinya dckarena tidak memiliki rperintah ... :-(
1
Bagaimana dengan: [[(if)2Q]si(condition)i(else)]x- membungkus semuanya dalam makro, dan jika-bagian di dalam makro lain di dalamnya, sehingga Anda bisa mencari 2Qjalan keluar dari semuanya sebelum mencapai bagian-lain. Jadi jika Anda ingin melakukannya jika 1 == 1 kemudian cetak 1 lagi cetak 2 , itu akan menjadi 1[[1P2Q]si1=i2P]x(belum diuji karena saya tidak memiliki akses ke dc di sini dan sekarang. Juga yakin saya telah melakukan trik ini dalam jawaban di sini sebelum tetapi tidak dapat menemukannya)
daniero
Yup, saya melakukan matematika, saran saya lebih pendek. Dengan contoh yang sama dan "notasi", dan menghapus spasi itu [/*else*/]sE[[/*then*/]sE]sIlalb=IlExvs [[/*then*/2Q]sIlalb=I/*else*/]x- 6 byte perbedaan. Masih belum diuji: P
daniero
1
Kerja bagus, @daniero! Saya akan memperbarui posting ketika saya punya waktu, atau Anda dapat melakukannya jika Anda mau.
Joe
5

Anda dapat menyimpan input dengan d

Dengan menggunakan d, yang menduplikasi ToS (atas tumpukan) Anda dapat memindahkan input dari jalan untuk digunakan nanti, sementara masih bisa menggunakannya.

Rɪᴋᴇʀ
sumber
@NoOneIsHere oh keren !!! Terima kasih!
Rɪᴋᴇʀ
5

Array

Meskipun mereka sakit kepala untuk pemula, dcmenawarkan array. Mereka bekerja seperti ini:

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

Seperti biasa, elemen pertama memiliki indeks 0. Array dapat berguna ketika bekerja dengan urutan, seperti pada urutan SUDSI , terutama dalam kombinasi dengan penghitung. Array dapat mengurangi jumlah pengocokan angka yang perlu Anda lakukan (dan jumlah penghitung dan perbandingan) jika Anda ingin memilih elemen tertentu tanpa merusak lingkungan Anda. Misalnya, jika Anda ingin memindahkan setumpuk angka ke dalam array, Anda bisa menulis fungsi rekursif yang menggunakan z(kedalaman tumpukan) atau z 1-sebagai indeks, menyimpan elemen, dan memeriksa apakah z == 0akan mengakhiri sendiri.

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

Waspadai hal-hal berikut:

  • Array dikaitkan dengan instance pada tumpukan bernama. Jika Anda mendorong nilai baru pada tumpukan yang memiliki larik yang dikaitkan dengannya, larik itu juga akan "didorong kembali", dan larik "baru" akan menggantikannya. Array lama tidak akan dapat digunakan sampai nilai yang sesuai pada stack bernama juga dapat digunakan (yaitu, di atas stack-nya). Ini adalah konsep yang rumit yang akan lebih baik dijelaskan dengan animasi yang bagus, yang berada di luar jangkauan saya.
  • Anda bisa menyimpan barang-barang di array bernama tanpa benar-benar mendorong nilai ke register bernama yang sesuai. Namun, jika Anda melakukan ini, Anda tidak dapat mengakses tumpukan / daftar dengan nama itu selama sisa sesi. dcakan crash.
  • Jika Anda menghapus nilai dari tumpukan yang dinamai, nilai apa pun dalam array terkait akan hilang — tidak ada peringatan, tidak ada perlindungan, tidak ada apa pun. Baru saja pergi (yang juga bisa bermanfaat).
Joe
sumber
Kerja bagus dengan tips DC!
R
dcmungkin telah diperbarui baru-baru ini, dan perilaku array mungkin telah sedikit berubah sehubungan dengan mogok. Tidak dapat mengkonfirmasi sekarang, tapi saya pikir ada sesuatu yang berbeda terakhir kali saya menggunakannya di Linux.
Joe
1
Jika Anda mencoba membaca indeks dari array yang belum disetel, Anda mendapatkan 0 dan bukan kesalahan. Yang bisa sangat berguna, tetapi juga patut diperhatikan jika Anda berpotensi menempatkan 0s dalam array ... Anda akan memerlukan cara lain untuk menguji bahwa indeks telah disentuh.
brhfl
5

0 pangkat ke-n bukannya kondisional / makro

Kadang-kadang Anda mungkin perlu sesuatu seperti ternary kondisional:

A == B ? C : D;

Cara yang bagus untuk menangani ini dijelaskan dalam jawaban @ Joe . Namun kami dapat melakukan yang lebih baik:

0AB-^E*C+

dimana E adalah D - C.

Ini menguji kesetaraan dengan menaikkan 0 pangkat selisih dua nilai. Ini menghasilkan 1 jika sama dan 0 sebaliknya. Sisanya hanya menskala 1 atau 0 ke nilai C atau D. Ini berfungsi karena dcmemberi 0 0 = 1 dan 0 n = 0 untuk n! = 1.

Trauma Digital
sumber
4

Kadang-kadang perlu untuk membuang nomor dari tumpukan. Salah satu cara untuk melakukan ini adalah dengan hanya memasukkannya ke variabel yang tidak digunakan, yaitu st. Namun dalam beberapa situasi, Anda dapat memindahkannya ke beberapa tempat lain, misalnya basis input ketika Anda tidak memiliki input numerik atau ke specifier presisi jika Anda tidak memiliki operasi lagi untuk dilakukan di mana presisi akan membuat perbedaan. Dalam kasus sebelumnya, gunakan i. Dalam kasus terakhir, gunakan k.

Trauma Digital
sumber
Jika output numerik tidak penting, odapat digunakan juga. Dan jika salah satu dari hal-hal ini tidak penting, mereka dapat digunakan sebagai penyimpanan dan juga hanya membuang - I/ K/ Omemanggil mereka masing-masing, dan menyimpan byte lebih dari sa/ ladll. Nilai valid AFAIK: i2-16; kbilangan bulat tidak negatif; obilangan bulat apa pun yang lebih besar dari 1.
brhfl
4

Panjang Perhitungan: Z, X, danz

Zmuncul ToS dan mendorong jumlah digit (desimal) jika itu adalah angka atau jumlah karakter jika itu adalah string. Ini bisa berguna untuk mendeteksi panjang hasil (untuk buffering output) atau menghitung panjang string. Perhatikan bahwa untuk angka, Ztekan panjang gabungan bagian integer dan bagian pecahan.

Xmuncul ToS dan mendorong jumlah digit di bagian fraksi nomor. Jika ToS adalah string, 0didorong.

Untuk menemukan jumlah digit di bagian bilangan bulat dari angka, orang dapat menggunakan dZrX-. Jika Anda belum mengubah presisi dari default k==0, penggunaannya 1/Zlebih pendek, tetapi anggap Anda perlu mempertahankan presisi non-nol tertentu setelah operasi: Kr0k1/Zrkagak merusak pemandangan.

zmendorong jumlah item pada tumpukan. Salah satu perintah favorit saya, sebenarnya tidak memunculkan nilai apa pun! Ini bisa digunakan untuk menghasilkan urutan angka atau menambah penghitung. Menggunakan zdberulang kali (katakanlah, pada awal makro) dapat membiarkan seseorang menguji perhitungan pada setiap bilangan alami atau keseluruhan dalam urutan menaik.

Joe
sumber
Telah digunakan zuntuk ini dan itu sebelumnya, tetapi tidak pernah terpikir oleh saya untuk menggunakannya sebagai
retasan
4

Digit Auntuk Fdapat digunakan sebagai pengganti angka 10 sampai 15. Namun mereka harus tetap diperlakukan secara efektif sebagai basis 10 digit (dengan asumsi basis input adalah 10) ketika di tempat yang berbeda. Dengan kata lain, dengan basis input 10 FFtidak akan mewakili 255, itu akan mewakili (15 * 10) + 15atau 165.

Bahkan ini bekerja untuk semua digit 0ke Fdalam dasar masukan 2ke 16. Jadi jika basis input 5, maka 26Eakan menjadi (2 * 5^2) + (6 * 5) + 14, atau 94.

Perhatikan bahwa perilaku ini berlaku untuk sumber GNU yang tidak dimodifikasi. Namun, seperti yang ditunjukkan oleh @SophiaLechner, distro berbasis RedHat tampaknya menggunakan bc-1.06-dc_ibase.patch yang mengubah perilaku ini sehingga digit> = ibase diperlakukan sebagai ibase - 1, terlepas dari nilai aktualnya. Perhatikan bahwa TIO dc tampaknya tidak memiliki bc-1.06-dc_ibase.patch (meskipun Fedora 28 ¯_ (ツ) _ / ¯).

Trauma Digital
sumber
Ini tidak tepat - meskipun satu digit di atas basis input ditafsirkan seperti yang Anda harapkan, jika literal memiliki beberapa digit, atau bahkan titik desimal, angka yang tidak valid untuk basis ditafsirkan sebagai (basis-1). Jadi pada basis input 10 FFmewakili 99, pada input dasar 5 26Esama dengan 244, yaitu basis 10 74.
Sophia Lechner
@SophiaLechner Anda yakin? tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A yang dcversi yang Anda berlari? Saya menggunakan GNU dc 1.4.1 di ubuntu dan GNU dc 1.3 di MacOS
Digital Trauma
Menarik. Saya menjalankan 1.3.95 di Red Hat, dan inilah program sampel Anda: [slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep' 99 74 [slechner @ XXX] $ dc --versi dc (GNU bc 1.06 .95) 1.3.95
Sophia Lechner
Argh ... tidak dapat membuat blok kode berfungsi dalam komentar. Intinya adalah bahwa FFpoutput 99dalam 1.3.95. Bisakah Anda memeriksanya dalam versi MacOS Anda?
Sophia Lechner
1
Tentu saja! Terima kasih atas semua penelitiannya.
Sophia Lechner
2

Saat menginisialisasi makro fungsi (kami akan menggunakan F) yang ingin Anda jalankan segera, gunakan sesuatu seperti dsFxdaripada sFlFx. Hal yang sama berlaku untuk variabel: dsadaripada sala.

Jika Anda perlu melakukan hal-hal lain di antara penyimpanan dan pemuatan (misalnya, sa[other stuff]la), masih mempertimbangkan apakah hal di atas layak: Jika Anda meninggalkan nilai pada tumpukan sebelum operasi lain, apakah akan kembali di atas pada akhir operasi itu?

Joe
sumber
2

Baru saja menemukan ini secara tidak sengaja. Namun cara lain untuk menghasilkan nol: _.

_adalah sinyal ke dc bahwa angka-angka berikut adalah angka negatif. Contoh:

_3 # pushes -3

Tetapi bagaimana jika kita tidak mengikutinya dengan angka?

_ # pushes 0...sometimes

Ini berfungsi ketika karakter non-kosong berikutnya yang mengikuti garis bawah bukan digit. Jika angka mengikutinya, bahkan setelah baris baru, itu ditafsirkan sebagai tanda negatif.

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
sumber
1

Jika isi seluruh tumpukan perlu dicetak di akhir program, loop makro rekursif dapat digunakan untuk mencapai ini. Namun, jauh lebih singkat untuk hanya menggunakan fperintah.

Trauma Digital
sumber
1

dcmembaca input baris pada satu waktu. Jika Anda perlu membaca dalam banyak item, melakukannya satu per baris mengharuskan ?setiap baris dibaca, atau loop makro yang rumit. Sebaliknya, jika semua item input dapat diletakkan pada satu baris yang dipisahkan oleh spasi, maka satu ?akan membaca semua item input, mendorong masing-masing ke stack.

Misalnya dalam seq 10 | dc -e'?f', seqoutput bilangan bulat 1-10, satu per baris. yang ?hanya akan membaca pertama 1yang akan menjadi output saat fkesedihan seluruh stack. Namun seq 10 | tr '\n' ' ' | dc -e'?f', trmembuat bilangan bulat input semua ruang terpisah. Dalam hal ini, ?akan membaca semua bilangan bulat dari baris dalam sekali jalan, dan fakan menampilkan semuanya.

Trauma Digital
sumber
1

Jika operator dibatasi dari sumber, buat yang baru dengan a

Sesuatu yang berguna bagi saya beberapa kali sekarang adalah untuk menghindari penggunaan operator tertentu dengan mendorong nilai ASCII dari operator, menggunakan auntuk mengubahnya menjadi string, dan smemasukkannya dalam register untuk dieksekusi sebagai makro nanti di. Sebagai contoh, saya perlu melakukan pembagian, tetapi saya tidak diperbolehkan atau mencoba menghindari menggunakan karakter /. Saya bisa, sebaliknya lakukan 47asddan kemudian di masa depan ketika saya perlu membagi 16 dengan 4 16 4 ldx,.

  • Ini hanya akan berfungsi untuk operator karakter tunggal (tidak dapat membangun string), dan tidak akan bekerja untuk perintah seperti situ yang perlu diperbaiki oleh sesuatu.
  • Ini menambahkan beberapa byte, dan karena itu hanya cocok ketika menghindari karakter tertentu diperlukan atau entah bagaimana memberi bonus skor.
brhfl
sumber
1

Menghindari spasi putih

Menghindari spasi putih muncul dalam beberapa tantangan, dan umumnya mudah dc. Selain dari string, satu waktu yang sangat spesifik yang spasi menjadi perlu adalah ketika mendorong beberapa nomor berturut-turut: 1 2 3. Jika ini harus dihindari:

  • Mengeksekusi makro kosong di antara: 1[]x2[]x3[]x.
  • Jika kurung adalah dari meja, menyimpan NOP dari depan makro waktu: 35asndan melaksanakan itu di antara: 1lnx2lnx3lnx.
brhfl
sumber
Anda juga dapat koma nomor yang terpisah, jika Anda bersedia memasang dc: ',' (054) unimplementedperingatan.
Trauma Digital
Saya tidak memikirkan itu - mungkin itu berlaku untuk token yang diberikan yang tidak menyelesaikan perintah ... menarik ...
brhfl