Kalkulator gerbang logika sederhana

9

Misi Anda, jika Anda memilih untuk menerimanya, adalah untuk membangun evaluator kebenaran sederhana untuk operator logis berikut:

----------------------------------------------------------------------------------
  Logical Name          |  Gate Name   |  Symbol  |  Symbol Name  |  Truth Table
----------------------------------------------------------------------------------
  Identity              |  is          |          |  (none)       |  10
  Negation              |  not         |    ~     |  tilde        |  01
  Conjunction           |  and         |    &     |  ampersand    |  1000
  Disjunction           |  or          |    |     |  pipe         |  1110
  Negative Conjunction  |  nand        |    ^     |  caret        |  0111
  Joint Denial          |  nor         |    v     |  "vee"        |  0001
  Exclusive Disjunction |  xor         |    x     |  "ecks"       |  0110
  Equivalence           |  equals/xnor |    =     |  equals       |  1001
  Implication           |  implies     |    >     |  greater than |  1011

Tabel kebenaran berada dalam urutan sebagai berikut:

  1. 1 1
  2. 1 0
  3. 0 1
  4. 0 0

Input akan muncul sebagai string sederhana 0, 1, dan simbol. Anda dapat menerima input sebagai parameter atau membacanya dari pengguna di stdin. Berikut adalah beberapa pasangan input / output sampel:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

Operator unary (negasi) akan selalu muncul sebelum nilai boolean, sedangkan operator biner akan selalu muncul di antara dua nilai boolean. Anda dapat mengasumsikan bahwa semua input akan valid. String adalah string ASCII biasa.

Jika Anda suka, Anda dapat menggunakan T dan F daripada 1 dan 0. -6 untuk jumlah karakter Anda jika Anda mendukung keduanya.

Ini adalah : kode terpendek dalam bahasa apa pun menang!

asteri
sumber
3
Saya percaya ^nama simbol harus diucapkan caret .
FireFly
3
@FireFly Haha, Anda benar. Terlalu dekat dengan makan siang! Terima kasih.
asteri

Jawaban:

6

APL (45 - 6 = 39)

⍎(1+9≠L)⌷¨↓⍉Z⍪⍉⍪'10∧∨⍲⍱≠≤*'[L←'TF&|^vx>'⍳Z←⍞]

Mendukung Tdan Fsebagai input tetapi akan selalu menampilkan 0atau 1.

Penjelasan:

  • Z←⍞: baca baris dan simpan di Z
  • L←'TF&|^vx>'⍳Z: Mendapatkan indeks di 'TF&|^vx>'untuk setiap karakter dalam Z, memberikan 9jika karakter tidak di 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: cari karakter yang sesuai di '10∧∨⍲⍱≠≤*'. (Jadi karakter yang tidak ada dalam daftar pertama menjadi *).
  • ↓⍉Z⍪⍉⍪: buat ini menjadi sebuah matriks, letakkan yang asli ( Z) di atasnya, dan pisahkan menjadi daftar string, di mana karakter pertama adalah asli dan karakter kedua adalah terjemahannya, jika ada.
  • (1+9≠L)⌷¨: untuk setiap string ini, dapatkan karakter pertama jika tidak ada terjemahan (jika L=9di tempat itu) dan karakter kedua jika ada.
  • Contoh: jika input telah T|0, kita akan memiliki 1∨0sekarang yang merupakan ekspresi APL yang sesuai
  • : eval

Catatan: ~dan =sudah melakukan hal yang benar sehingga mereka tidak perlu diganti oleh apa pun.

marinus
sumber
Sangat bagus! Ini adalah pendekatan translate-to-APL-and-eval, kan? Saya sedang mempertimbangkan pendekatan berbasis gerund di J, tetapi saya tidak tahu bagaimana cara cerdik memisahkan operan. : \
FireFly
Mengapa manipulasi matriks ketika Anda bisa menambahkan aturan terjemahan untuk karakter tanpa perubahan ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Nilai 33-6 = 27)
TwiNight
8

C - 165 127

Itu tadi menyenangkan! Tabel pencarian biasa mengandalkan offset tetap untuk pencarian.

main(){
  char*s="100011001110110v& x = |^> /~",
       t[6]="0/xxx",
      *u= strchr((gets(t+2),t),0)-3;
  putchar(strchr(s,u[1])[*u*2+u[2]-159]);
}

Untuk beberapa alasan getstidak mendapatkan secara implisit menyatakan, jadi ketika saya dihapus termasuk saya harus mengubah gets(t+2)ke (gets(t+2),t)(atau sama di tempat lain, biaya sebanyak).


Penjelasan

Pertama-tama, karena tabel kebenaran untuk operator memiliki banyak karakter yang tumpang tindih, kami ingin menyimpan tabel pencarian dengan cara sehingga kami memungkinkan tumpang tindih. Inilah cara saya memilih untuk menyimpannya:

v    &    x    =    |    ^    >       ~     (operation)
1000 0001 0110 1001 0111 1110 1101 01 10    (truth table [order 00,01,10,11])
0    1    3    5    7    8    9    B  D     (offset in LUT below)

0123456789ABCDE   (offsets)
100011001110110   (values)

Selanjutnya, kami ingin memetakan simbol operator ke offset ini. Kami melakukan ini dengan menyimpan simbol operator dalam string yang sama pada offset tetap dari data LUT (yaitu, 16 karakter kemudian, yaitu langsung setelah data LUT). Proses pencarian adalah "cari operator s, kurangi 16, tambahkan left*2+right(operan kiri / kanan). Untuk pencarian" operasi identitas "kosong, karena cara input diambil operator dalam hal ini akan menyelesaikan apa pun t[1]yang diinisialisasi untuk- -dalam kasus kami /. jadi, kami menggunakan /sebagai kunci tabel untuk mewakili operasi identitas. Ketika kita memproses unary ~operasi " left" (untuk perhitungan lookup disebutkan sebelumnya) selalu yang sama / . /terjadi menjadi salah satu kurang dari0ASCII-wise, artinya ketika kita mengkompensasi digit ASCII \akan mewakili -1. Garis miring di area kunci tabel pencarian (karakter kedua hingga terakhir s, yaitu) diposisikan untuk mengimbangi ini.

Selanjutnya, penanganan input. Input memiliki panjang dinamis, tetapi akan lebih mudah jika kita memiliki nama statis spesifik untuk operan kiri, operator dan operan kanan, terlepas dari input. Jika kita berpura-pura bahwa kita dapat membaca input dari kanan ke kiri, ini pada dasarnya akan terjadi secara otomatis - operan kanan selalu merupakan karakter paling kanan, operator (jika ada) adalah kedua-ke-paling kanan, operan kiri (jika ada ) adalah dari ketiga ke kanan. Untuk dapat mengindeks string seperti ini, kami menggunakan strchruntuk menemukan \0terminator ( - 3untuk mempermudah pengindeksan). Ini menunjukkan mengapa t[0]dan t[1]menjadi operan / operator kiri masing-masing ketika inputnya 1 atau 2 karakter.

Menyatukannya, hasilnya akan menjadi putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), tetapi beberapa refactoring dan lipat konstan malah membuat kita lebih pendek putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).

FireFly
sumber
Bisakah Anda menjelaskan cara kerjanya?
Johannes Kuhn
Tabel kebenaran tumpang tindih adalah ide yang brilian. Tidak akan pernah memikirkan itu sendiri. :)
asteri
Juga bacaan dari kanan ke kiri. Saya tahu input panjang variabel dan pemosisian akan menimbulkan tantangan, dan itu cara yang bagus untuk menyelesaikannya. Pemikiran out-of-the-box yang sangat bagus. Ingin bekerja di tim pengembangan saya? Haha
asteri
4
Saya pikir lebih banyak jawaban harus memiliki penjelasan seperti ini. Bantu kami yang masih belajar sedikit! (Dan oleh mereka yang masih belajar berarti banyak orang)
agweber
@agweber: Senang mendengarnya, saya agak khawatir dengan penjelasan saya. Dan ya, mungkin semua orang di sini dalam fase "masih belajar" .. well, setidaknya saya tahu saya.
FireFly
4

Tcl, 212 208-6 = 202

proc o n\ e {proc $n a\ b expr\ $e}
o > {$a<=$b}
o v {!($a|$b)}
o x {$a^$b}
o ^ {!($a&$b)}
namespace pat tcl::mathop 
lmap o\ b [lassign [split [string map {~0 1 ~1 0} $argv] {}] a] {set a [$o $a $b]}
puts $a

Tidak Disatukan:

# Defines an operator
proc operator {name expression} {
    proc $name {a b} "expr $expression"
}
operator > {$a<=$b}
operator v {!($a|$b)}
operator x {$a^$b}
operator ^ {!($a&$b)}
# Call the commands in ::tcl::mathop if the command is not in the global namespace
namespace path tcl::mathop
# lmap instead foreach
# assume that we only got 1 argument.
foreach {op b} [lassign [string map {{~ 0} 1 {~ 1} 0} [split $argv {}]] a] {
   set a [$op $a $b]
}
puts $a

Saya pikir garis depan perlu penjelasan:

  • split $argv {} memisahkan string input (sebenarnya adalah daftar, tetapi kode-golf) menjadi karakter itu.
  • string map {{~ 0} 1 {~ 1} 0} ...mengambil string dan menggantikan ~ 0dengan 1dan ~ 1dengan0
  • lassign ... a mengambil elemen pertama dari daftar dan menugaskannya ke variabel a, mengembalikan sisanya.
  • foreach {op b} ... {code}berjalan di atas daftar dan mengambil 2 elemen setiap kali: opdanb
  • set a [$op $a $b]mengeksekusi perintah dalam variabel op, menyimpan hasilnya dalama
Johannes Kuhn
sumber
3

JavaScript - 107 105 karakter

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
sumber
Haha bagus. Itu berguna. Bahkan tidak memikirkan eval()ketika saya mengada-ada. Beri aku sedikit untuk pulang dan mengujinya.
asteri
1
nand = &~dan juga = |~?
Johannes Kuhn
@ Johnannes: Ini tidak benar &~- benar dan |~, tetapi NAND hanyalah kebalikan dari AND. Jadi, inversing salah satu bit tidak membalikkan hasilnya juga.
ProgramFOX
3

Befunge-98 - 104 101 98-6 72

... karena setiap tugas membutuhkan solusi esolang .. terjemahan implementasi C saya, tetapi memproses karakter satu per satu.

#v~
2_vp5a00+*2%2\p10\%
0:<+1_v#-g5\g1
1_|#:\</2\-
.@>2%
 v   ~x^&=.>  |

Fakta yang menyenangkan: ganti @to a,$dan Anda akan mendapatkan REPL yang tidak pernah berakhir (meskipun, jika Anda melakukan ini, Anda akan melihat bahwa identitas sebenarnya "ulangi perintah terakhir dengan lhs = 0 dan rhs = input", yang kebetulan merupakan default untuk identitas ). REPL tidak ada lagi.

Tidak digabungkan (versi sebelumnya):

v10001100111011v& x = |^>~
  $       1111111111222222
 1234567890123456789012345

 [read input]
> ~ :a- #v_   $ 21g " "- + 0g , @

v p11:   <
   ↑save chr

0 ←lup   [traverse LUT]
> 1+  :11g  \0g -! #v_
 v                  <
    lup chr acc
v>  :3` #v_  $"0"-\2*+

               v>   . , a,
 v       <
v> 9+9+ 21p $

Sunting: terinspirasi oleh solusi @jpjacobs, saya sekarang mengandalkan posisi karakter dalam LUT untuk mewakili tabel kebenaran. Misalnya, |ada di posisi 1110 2 = 14 karena ini sesuai dengan tabel kebenaran untuk |.

FireFly
sumber
Itu gila. Ok, setiap solusi di befunge gila.
Johannes Kuhn
2

J - 65 67-6 = 61

Tidak ada lagi b. Kata keterangan. Tanpa menghitung penugasan fungsi: 67 karakter untuk versi TF, 63 untuk versi non-TF:

lgcTF =:".@({&('*+-+-<*01',.3 6#'.:')"1@n^:(9>n=:'&|~xv>^FT'&i.)@{.&.>&.;:)
lgc   =:".@({&('*+-+-<*',.3 4#'.:')"1@n^:(7>n=:'&|~xv>^'&i.)@{.&.>&.;:)

LgcTF menangani 0 dan 1 serta T dan F.

Mendukung semua sintaks J dalam hal kereta, tanda kurung, dan mengevaluasi secara ketat dari kanan ke kiri (tidak ada aturan prioritas lainnya).

Semua karakter yang tidak ada dalam daftar operator + Z tidak dapat digunakan, yang lain akan bertindak seperti dalam standar J (termasuk variabel).

Pemakaian:

NB.Assign TF anyhow
T=:1 [ F=: 0
lgc 'T & F'
0
lgc ' T ~@& F' NB. negation after and = nand
NB. make a truth table
d=: 0 1
lgc 'd ~@|/ d'
1 0
0 0 
NB. and so on... 
jpjacobs
sumber
1

Catatan tambahan 263

Gagasan Firefly diterjemahkan ke dalam Postscript.

{(0/xxx)dup 2 3 getinterval(%lineedit)(r)file exch 
readstring pop length 1 sub 3
getinterval(100011001110110v& x = |^> /~)dup
2 index 1 1 getinterval search pop exch pop exch pop 
length 3 2 roll{}forall exch pop exch 2 mul add 159 sub add 
1 getinterval =}loop

Bertakuk:

%!

{
    (0/xxx) dup 2 3 getinterval
    (%lineedit)(r)file exch % (0/xxx) file (xxx)
    readstring pop
    length % (0/xxx) len(x|xx|xxx)
    1 sub 3 getinterval % (0/x)|(/xx)|(xxx)
    (100011001110110v& x = |^> /~) dup
    2 index 1 1 getinterval search pop % (0/x)|(/xx)|(xxx) s post match pre
    exch pop exch pop % (xxx) s pre
    length 
    3 2 roll {} forall exch pop % s len(pre) u_0 u_2
    exch 2 mul add 159 sub add % s ind
    1 getinterval
    = flush
} loop
luser droog
sumber
1

Befunge-93, 86 karakter

Bekerja dengan hashing simbol kedua input (menemukan fungsi yang kompak dan menghindari tabrakan adalah beberapa pekerjaan) untuk koordinat, dan mengambil simbol pertama dan ketiga masing-masing modulo 2 sebagai dua bit paling signifikan dari koordinat x, maka mengambil nilai apa pun pada posisi yang ditunjukkan. Fungsi hash yang lebih baik atau metode penyimpanan / pengalamatan tabel kebenaran yang lebih ringkas hanyalah dua cara yang bisa dilakukan untuk mengurangi panjangnya.

~~~\:8/\5%:++00p2%\2%2*+00gg,@
0 1







1001
0001
1101
1

0
0110



1110
1000


0111
MDS
sumber