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 kode-golf umum yang setidaknya sedikit spesifik untuk dc (mis. Menghapus komentar bukanlah jawaban yang membantu)
Silakan kirim satu tip per jawaban.
Jawaban:
Pernyataan if-then-else
Misalkan kita ingin memeriksa kondisi
edit:a==b
(biarkana
danb
disimpan dalam register masing-masing bernama).Biarkan
(foo)
menjadi penampung, untuk tujuan kondensasi:Cukup yakin ini adalah pernyataan yang paling ringkas jika memungkinkan (juga ditampilkan di sini ).
sumber
[[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f
ini awal? Tindakan untuk tehn dan lainnya ada di stack,I
makro "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 4
hanyalah contoh data untuk dibandingkan. Atau yang[x]sI
bagian dapat dipindahkan ke perbandingan, jika dianggap lebih mudah dibaca:[[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f
. Dalamf
contoh hanya akan menunjukkan tat tumpukan bersih setelah ...dc
dan itu halaman 1 di mana saya melihat OpenBSDdc
'sif-then-else
konstruk. Saya pikir kita perludc
bundel penggemar dengan 3 rasa untuk semua sistem operasi utama ... o :-) ... danif-then-else
proposal saya di atas tidak berfungsi pada aslinyadc
karena tidak memilikir
perintah ... :-([[(if)2Q]si(condition)i(else)]x
- membungkus semuanya dalam makro, dan jika-bagian di dalam makro lain di dalamnya, sehingga Anda bisa mencari2Q
jalan keluar dari semuanya sebelum mencapai bagian-lain. Jadi jika Anda ingin melakukannya jika 1 == 1 kemudian cetak 1 lagi cetak 2 , itu akan menjadi1[[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)[/*else*/]sE[[/*then*/]sE]sIlalb=IlEx
vs[[/*then*/2Q]sIlalb=I/*else*/]x
- 6 byte perbedaan. Masih belum diuji: PAnda 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.sumber
Array
Meskipun mereka sakit kepala untuk pemula,
dc
menawarkan array. Mereka bekerja seperti ini: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) atauz 1-
sebagai indeks, menyimpan elemen, dan memeriksa apakahz == 0
akan mengakhiri sendiri.Waspadai hal-hal berikut:
dc
akan crash.sumber
dc
mungkin 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.0 pangkat ke-n bukannya kondisional / makro
Kadang-kadang Anda mungkin perlu sesuatu seperti c ternary kondisional:
Cara yang bagus untuk menangani ini dijelaskan dalam jawaban @ Joe . Namun kami dapat melakukan yang lebih baik:
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
dc
memberi 0 0 = 1 dan 0 n = 0 untuk n! = 1.sumber
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, gunakani
. Dalam kasus terakhir, gunakank
.sumber
o
dapat digunakan juga. Dan jika salah satu dari hal-hal ini tidak penting, mereka dapat digunakan sebagai penyimpanan dan juga hanya membuang -I
/K
/O
memanggil mereka masing-masing, dan menyimpan byte lebih darisa
/la
dll. Nilai valid AFAIK:i
2-16;k
bilangan bulat tidak negatif;o
bilangan bulat apa pun yang lebih besar dari 1.Panjang Perhitungan:
Z
,X
, danz
Z
muncul 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,Z
tekan panjang gabungan bagian integer dan bagian pecahan.X
muncul ToS dan mendorong jumlah digit di bagian fraksi nomor. Jika ToS adalah string,0
didorong.Untuk menemukan jumlah digit di bagian bilangan bulat dari angka, orang dapat menggunakan
dZrX-
. Jika Anda belum mengubah presisi dari defaultk==0
, penggunaannya1/Z
lebih pendek, tetapi anggap Anda perlu mempertahankan presisi non-nol tertentu setelah operasi:Kr0k1/Zrk
agak merusak pemandangan.z
mendorong 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. Menggunakanzd
berulang kali (katakanlah, pada awal makro) dapat membiarkan seseorang menguji perhitungan pada setiap bilangan alami atau keseluruhan dalam urutan menaik.sumber
z
untuk ini dan itu sebelumnya, tetapi tidak pernah terpikir oleh saya untuk menggunakannya sebagaiDigit
A
untukF
dapat 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 10FF
tidak akan mewakili 255, itu akan mewakili(15 * 10) + 15
atau 165.Bahkan ini bekerja untuk semua digit
0
keF
dalam dasar masukan2
ke16
. Jadi jika basis input 5, maka26E
akan 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 TIOdc
tampaknya tidak memiliki bc-1.06-dc_ibase.patch (meskipun Fedora 28 ¯_ (ツ) _ / ¯).sumber
FF
mewakili99
, pada input dasar 526E
sama dengan244
, yaitu basis 1074
.dc
versi yang Anda berlari? Saya menggunakan GNU dc 1.4.1 di ubuntu dan GNU dc 1.3 di MacOSFFp
output99
dalam 1.3.95. Bisakah Anda memeriksanya dalam versi MacOS Anda?Saat menginisialisasi makro
fungsi(kami akan menggunakanF
) yang ingin Anda jalankan segera, gunakan sesuatu sepertidsFx
daripadasFlFx
. Hal yang sama berlaku untuk variabel:dsa
daripadasala
.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?sumber
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:Tetapi bagaimana jika kita tidak mengikutinya dengan angka?
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.
sumber
Jika isi seluruh tumpukan perlu dicetak di akhir program, loop makro rekursif dapat digunakan untuk mencapai ini. Namun, jauh lebih singkat untuk hanya menggunakan
f
perintah.sumber
dc
membaca 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'
,seq
output bilangan bulat 1-10, satu per baris. yang?
hanya akan membaca pertama1
yang akan menjadi output saatf
kesedihan seluruh stack. Namunseq 10 | tr '\n' ' ' | dc -e'?f'
,tr
membuat bilangan bulat input semua ruang terpisah. Dalam hal ini,?
akan membaca semua bilangan bulat dari baris dalam sekali jalan, danf
akan menampilkan semuanya.sumber
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
a
untuk mengubahnya menjadi string, dans
memasukkannya 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 lakukan47asd
dan kemudian di masa depan ketika saya perlu membagi 16 dengan 416 4 ldx
,.s
itu yang perlu diperbaiki oleh sesuatu.sumber
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:1[]x2[]x3[]x
.35asn
dan melaksanakan itu di antara:1lnx2lnx3lnx
.sumber
dc: ',' (054) unimplemented
peringatan.