3 ile bölünebilirlik için bina devresi


12

TCS'deki bir boolean devresi temel olarak And, Or, Not kapılarından oluşan bir DAG'dır ve bilinen "işlevsel bütünlük" ile mümkün olan tüm fonksiyonları hesaplayabilirler. örneğin, bu bir ALU'nun temel ilkesidir .

Zorluk: 8-ikili basamaklı bir sayının 3 ile bölünebilir olup olmadığını belirlemek için bir devre oluşturun ve sonucunuzu bir şekilde görselleştirin (örneğin bir tür resimde)

Seçmenler için karar verme kriterleri, devreyi oluşturan kodun keyfi boyut sayılarına hoş bir şekilde genelleşip genelleşmediğine ve algoritmik olarak oluşturulan görselleştirmenin kompakt / dengeli ancak yine de insan tarafından okunabilir olup olmadığına (yani elle düzenlemeyle görselleştirmeye izin verilmez) dayanmaktadır . yani görselleştirme sadece n = 8 içindir, ancak kod ideal olarak tüm 'n' için çalışacaktır. kazanan giriş sadece en iyi oyu aldı.

Biraz benzer bir soru: NAND mantık kapılarını kullanarak bir çarpma makinesi oluşturun


2
Çok daha iyi. Ancak "genelleme" ve "estetik" nesnel değildir. Tüm soruların objektif kazanma kriteri olmalıdır. Bu özellikleri uygulamak istiyorsanız, popülerlik yarışmasını kullanın. En kısa kodu istiyorsanız, code-golf kullanın. Bu ikisinin bir kombinasyonunu yapmak istiyorsanız, code-challenge kullanın, ancak bir formül belirtin. Örneğin, 1.25 * oy - 0.25 * uzunluk bu sorunun yaptığı gibi: codegolf.stackexchange.com/questions/23581/eiffel-tower-in-3d/…
Level River St

Tamam, istediğin chgs yaptı. geribildirim için teşekkürler.
Mart'ta vzn

Oghh, sanırım tüm optimizasyonlarının en kısa cevabı vermesi gerektiğinde derlenmiş VHDL veya Verilog. Daha sonra deneyeceğim.
Kirill Kulakov

1
Daha iyi kazanma kriterleri gate-golf olacaktır
TheDoctor

@Doktor ??? nedir gate-golf? bu etiket mevcut değil. katılımcılara not: lütfen hangi dili / görselleştirme aracını kullandığınızı belirtin. başka kimse plz yorumu girmek istiyorsa. aksi halde kazanan toniti kabul eder. şimdiye kadar katılımcılara thx bu beklenenden daha iyi "BTE" gitti!
14'te vzn

Yanıtlar:


7

hesaplamak için devre modulo 3

Grafik, her i düzeyinde 3 boolean tutar. Sayının yüksek dereceli i bitlerinin 0, 1 veya 2 mod 3'e eşit olduğu gerçeğini temsil ederler. Her seviyede, önceki üç biti ve bir sonraki giriş bitini temel alarak sonraki üç biti hesaplıyoruz.

Grafiği oluşturan python kodu. Sadece farklı sayıda bit almak için N'yi veya farklı bir modül elde etmek için K'yi değiştirin. Görüntüyü oluşturmak için noktadan python programının çıktısını çalıştırın .

N = 8
K = 3
v = ['0']*(K-1) + ['1']
ops = {}

ops['0'] = ['0']
ops['1'] = ['1']
v = ['0']*(K-1) + ['1']
for i in xrange(N):
  ops['bit%d'%i] = ['bit%d'%i]
  ops['not%d'%i] = ['not','bit%d'%i]
  for j in xrange(K):
    ops['a%d_%d'%(i,j)] = ['and','not%d'%i,v[(2*j)%K]]
    ops['b%d_%d'%(i,j)] = ['and','bit%d'%i,v[(2*j+1)%K]]
    ops['o%d_%d'%(i,j)] = ['or','a%d_%d'%(i,j),'b%d_%d'%(i,j)]
  v = ['o%d_%d'%(i,j) for j in xrange(K)]

for i in xrange(4):
  for n,op in ops.items():
    for j,a in enumerate(op[1:]):
      if ops[a][0]=='and' and ops[a][1]=='0': op[j+1]='0'
      if ops[a][0]=='and' and ops[a][2]=='0': op[j+1]='0'
      if ops[a][0]=='and' and ops[a][1]=='1': op[j+1]=ops[a][2]
      if ops[a][0]=='and' and ops[a][2]=='1': op[j+1]=ops[a][1]
      if ops[a][0]=='or' and ops[a][1]=='0': op[j+1]=ops[a][2]
      if ops[a][0]=='or' and ops[a][2]=='0': op[j+1]=ops[a][1]

for i in xrange(4):
  used = set(['o%d_0'%(N-1)])|set(a for n,op in ops.items() for a in op[1:])
  for n,op in ops.items():
    if n not in used: del ops[n]

print 'digraph {'
for n,op in ops.items():
  if op[0]=='and': print '%s [shape=invhouse]' % n
  if op[0]=='or': print '%s [shape=circle]' % n
  if op[0]=='not': print '%s [shape=invtriangle]' % n
  if op[0].startswith('bit'): print '%s [color=red]' % n
  print '%s [label=%s]' % (n,op[0])
  for a in op[1:]: print '%s -> %s' % (a,n)
print '}'

harika! graphviz dekullandık... küçük kelime oyunu, diyagramda kullanılmayan AND / ORs vardır. ayrıca konumlarını göstermek için farklı renkteki giriş bitlerini vurgulamanızı öneririz
vzn

@vzn: Tamam, düzeltildi.
Keith Randall

12

Derinlik: 7 (logaritmik), 18x AND, 6x OR, 7x XOR, 31 kapı (doğrusal)

Dört numaralı, modulo üç içindeki rakam toplamını hesaplayayım:

Açıkça görülebilen hiyerarşik yapıya sahip 7 katmanlı devre

Logisim'de çizilmiş devre

Genelleme, resmi olarak (umarım biraz okunabilir):

balance (l, h) = {
  is1: l & not h,
  is2: h & not l,
}

add (a, b) = 
  let aa = balance (a.l, a.h)
      bb = balance (b.l, b.h)
  in  { l:(a.is2 & b.is2) | (a.is1 ^ b.is1),
        h:(a.is1 & b.is1) | (a.is2 ^ b.is2)}

pairs [] = []
pairs [a] = [{h:0, l:a}]
pairs [rest.., a, b] = [pairs(rest..).., {h:a, l:b}]

mod3 [p] = p
mod3 [rest.., p1, p2] = [add(p1, p2), rest..]

divisible3 number =
  let {l: l, h: h} = mod3 $ pairs number
  in  l == h

şimdi ingilizce:

Sayıda ikiden fazla bit olsa da, en düşük iki bit çiftini alın ve modulo 3'ü toplayın, ardından sonucu sayının arkasına ekleyin, ardından son çift sıfır modulo 3 ise geri dönün. Sayıdaki bit sayısı, üstüne ekstra sıfır bit ekleyin, ardından sabit değer yayılımıyla parlatın.

Önde yerine arkaya eklemek, ekleme ağacının bağlantılı bir liste yerine dengeli bir ağaç olmasını sağlar. Bu da, bit sayısında logaritmik derinlik sağlar: beş kapı ve çift iptal için üç seviye ve sonunda ekstra bir kapı.

Tabii ki, yaklaşık düzlemsellik isteniyorsa, üst çifti değiştirmeden ön tarafa sarmak yerine bir sonraki katmana geçirin. Bununla birlikte, bu söylenenden daha kolaydır (sözde kodda bile). Bir sayıdaki bit sayısı iki güçse (Mart 2014 itibariyle herhangi bir modern bilgisayar sisteminde olduğu gibi), yalnız çiftler oluşmaz.

Layouter konumu koruyorsa / rota uzunluğu en aza indiriyorsa, devreyi okunabilir tutmalıdır.

Bu Ruby kodu, herhangi bir sayıda bit (hatta bir) için bir devre şeması oluşturur. Yazdırmak için Logisim'de açın ve resim olarak dışa aktarın:

require "nokogiri"

Port = Struct.new :x, :y, :out
Gate = Struct.new :x, :y, :name, :attrs
Wire = Struct.new :sx, :sy, :tx, :ty

puts "Please choose the number of bits: "
bits = gets.to_i

$ports = (1..bits).map {|x| Port.new 60*x, 40, false};
$wires = [];
$gates = [];

toMerge = $ports.reverse;

def balance a, b
y = [a.y, b.y].max
$wires.push Wire.new(a.x   , a.y , a.x   , y+20),
          Wire.new(a.x   , y+20, a.x   , y+40),
          Wire.new(a.x   , y+20, b.x-20, y+20),
          Wire.new(b.x-20, y+20, b.x-20, y+30),
          Wire.new(b.x   , b.y , b.x   , y+10),
          Wire.new(b.x   , y+10, b.x   , y+40),
          Wire.new(b.x   , y+10, a.x+20, y+10),
          Wire.new(a.x+20, y+10, a.x+20, y+30)
$gates.push Gate.new(a.x+10, y+70, "AND Gate", negate1: true),
          Gate.new(b.x-10, y+70, "AND Gate", negate0: true)
end

def sum (a, b, c, d)
y = [a.y, b.y, c.y, d.y].max
$wires.push Wire.new(a.x   , a.y , a.x   , y+40),
          Wire.new(a.x   , y+40, a.x   , y+50),
          Wire.new(a.x   , y+40, c.x-20, y+40),
          Wire.new(c.x-20, y+40, c.x-20, y+50),
          Wire.new(b.x   , b.y , b.x   , y+30),
          Wire.new(b.x   , y+30, b.x   , y+50),
          Wire.new(b.x   , y+30, d.x-20, y+30),
          Wire.new(d.x-20, y+30, d.x-20, y+50),
          Wire.new(c.x   , c.y , c.x   , y+20),
          Wire.new(c.x   , y+20, c.x   , y+50),
          Wire.new(c.x   , y+20, a.x+20, y+20),
          Wire.new(a.x+20, y+20, a.x+20, y+50),
          Wire.new(d.x   , d.y , d.x   , y+10),
          Wire.new(d.x   , y+10, d.x   , y+50),
          Wire.new(d.x   , y+10, b.x+20, y+10),
          Wire.new(b.x+20, y+10, b.x+20, y+50)
$gates.push Gate.new(a.x+10, y+90, "XOR Gate"),
          Gate.new(b.x+10, y+80, "AND Gate"),
          Gate.new(c.x-10, y+80, "AND Gate"),
          Gate.new(d.x-10, y+90, "XOR Gate")
$wires.push Wire.new(a.x+10, y+90, a.x+10, y+100),
          Wire.new(b.x+10, y+80, b.x+10, y+90 ),
          Wire.new(b.x+10, y+90, a.x+30, y+90 ),
          Wire.new(a.x+30, y+90, a.x+30, y+100),
          Wire.new(d.x-10, y+90, d.x-10, y+100),
          Wire.new(c.x-10, y+80, c.x-10, y+90 ),
          Wire.new(c.x-10, y+90, d.x-30, y+90 ),
          Wire.new(d.x-30, y+90, d.x-30, y+100)
$gates.push Gate.new(d.x-20, y+130, "OR Gate"),
          Gate.new(a.x+20, y+130, "OR Gate")
end

def sum3 (b, c, d)
y = [b.y, c.y, d.y].max
$wires.push Wire.new(b.x   , b.y , b.x   , y+20),
          Wire.new(b.x   , y+20, b.x   , y+30),
          Wire.new(b.x   , y+20, d.x-20, y+20),
          Wire.new(d.x-20, y+20, d.x-20, y+30),
          Wire.new(c.x   , c.y , c.x   , y+60),
          Wire.new(c.x   , y+60, b.x+30, y+60),
          Wire.new(b.x+30, y+60, b.x+30, y+70),
          Wire.new(d.x   , d.y , d.x   , y+10),
          Wire.new(d.x   , y+10, d.x   , y+30),
          Wire.new(d.x   , y+10, b.x+20, y+10),
          Wire.new(b.x+20, y+10, b.x+20, y+30),
          Wire.new(b.x+10, y+60, b.x+10, y+70)
$gates.push Gate.new(b.x+10, y+60 , "AND Gate"),
          Gate.new(d.x-10, y+70 , "XOR Gate"),
          Gate.new(b.x+20, y+100, "OR Gate" )
end

while toMerge.count > 2  
puts "#{toMerge.count} left to merge"
nextToMerge = []
while toMerge.count > 3
 puts "merging four"
 d, c, b, a, *toMerge = toMerge
 balance a, b
 balance c, d
 sum *$gates[-4..-1]
 nextToMerge.push *$gates[-2..-1] 
end
if toMerge.count == 3
 puts "merging three"
 c, b, a, *toMerge = toMerge
 balance b, c
 sum3 a, *$gates[-2..-1]
 nextToMerge.push *$gates[-2..-1]
end
nextToMerge.push *toMerge
toMerge = nextToMerge
puts "layer done"
end

if toMerge.count == 2
b, a = toMerge
x = (a.x + b.x)/2
x -= x % 10
y = [a.y, b.y].max
$wires.push Wire.new(a.x , a.y , a.x , y+10),
          Wire.new(a.x , y+10, x-10, y+10),
          Wire.new(x-10, y+10, x-10, y+20),
          Wire.new(b.x , b.y , b.x , y+10),
          Wire.new(b.x , y+10, x+10, y+10),
          Wire.new(x+10, y+10, x+10, y+20)
$gates.push Gate.new(x, y+70, "XNOR Gate")
toMerge = [$gates[-1]]
end

a = toMerge[0]
$wires.push Wire.new(a.x, a.y, a.x, a.y+10)
$ports.push Port.new(a.x, a.y+10, true)

def xy (x, y)
"(#{x},#{y})"
end
circ = Nokogiri::XML::Builder.new encoding: "UTF-8" do |xml|
xml.project version: "1.0" do
xml.lib name: "0", desc: "#Base"
xml.lib name: "1", desc: "#Wiring"
xml.lib name: "2", desc: "#Gates"
xml.options
xml.mappings
xml.toolbar do
  xml.tool lib:'0', name: "Poke Tool"
  xml.tool lib:'0', name: "Edit Tool"
end #toolbar
xml.main name: "main"
xml.circuit name: "main" do
  $wires.each do |wire|
    xml.wire from: xy(wire.sx, wire.sy), to: xy(wire.tx, wire.ty)
  end #each 
  $gates.each do |gate|
    xml.comp lib: "2", name: gate.name, loc: xy(gate.x, gate.y) do
      xml.a name: "facing", val: "south"
      xml.a name: "size", val: "30"
      xml.a name: "inputs", val: "2"
      if gate.attrs
        gate.attrs.each do |name, value|
          xml.a name: name, val: value 
        end #each
      end #if
    end #comp
  end #each
  $ports.each.with_index do |port, index|
    xml.comp lib: "1", name: "Pin", loc: xy(port.x, port.y) do
      xml.a name: "tristate", val: "false"
      xml.a name: "output",   val: port.out.to_s
      xml.a name: "facing",   val: port.out ? "north" : "south"
      xml.a name: "labelloc", val: port.out ? "south" : "north"
      xml.a name: "label",    val: port.out ? "out" : "B#{index}"
    end #port
  end #each
end #circuit
end #project
end #builder

File.open "divisibility3.circ", ?w do |file|
file << circ.to_xml
end

puts "done"

son olarak, 32 bit için bir çıktı oluşturması istendiğinde, düzenleyicim bunu üretir. Kuşkusuz, çok geniş girişler için çok kompakt değildir:

Boşa çok fazla alan içeren 13 katmanlı canavarlık


gerçekten harika görünüyor & şimdiye kadar en iyi devre / düzen. kod hangi dilde? Varsa hangi katmanı kullandınız? düzenleyicinin bir algoritma olması istendi ve belirtilmedikçe algoritmanın (el düzeni) kullanılmadığını varsaymak zorundayız ...
vzn

@ vzn düzenleyici de uygulanmalı mıydı? Kısıtlamanın, diyagramı elle çizebileceğimiz anlamına geldiğini, ancak okunabilirliğin, diyagramın çizilme şekline bağlı olmaması gerektiğini anladım. TimWolla'nın devresi kesinlikle elle üretilir. Sözde kod çoğunlukla Javascripty nesneleri eklenmiş Haskell tabanlıdır.
John Dvorak

algoritmik olarak yaratılmış görselleştirme , temelde algoritmik düzenleyici anlamına geliyordu, ancak şimdi bunun belirsiz bir şekilde yorumlanabileceğini kabul ediyordu. kristal berraklığı olmadığı için özür dilerim. el düzeninize neredeyse benzer sonuçlar alabilecek otomatik bir düzenleyici biliyor musunuz?
vzn

Ne yazık ki hayır. yEd harika düzenleyicilere sahiptir ancak yönlendirmeyi yok sayar. Noktaya hiç aşina olmadım ve çıktısını tam olarak güzel bulmuyorum. Sanırım bu sahte kodu Ruby'ye çevirebilirim (kolay) ve logisim devresini dışa aktaracak kendi özel düzenleyicimi (çok zor değil, karmaşık) yazabilirim (sadece bir XML ve hatta gziple değil, çok kolay). Ben (istiyorum) ve bunu ayrı bir cevap olarak mı göndermeliyim? Ayrıca, bu elle tasarlanmış sayılır mı?
John Dvorak

Tüm iyi cevaplar, ama bu şimdiye kadarki en zarif gibi görünüyor
Digital Trauma

5

2 × 24 DEĞİL, 2 × 10 + 5 VE, 2 × 2 + 5 VEYA, 2 × 2 NOR

Bu tamamen ölçeklenmiyor. Hiç de değil. Belki onu geliştirmeye çalışacağım.

Bunu 30'a kadar olan sayılar için test ettim ve işe yaradı.

Bu 2 büyük devre aktif girişlerin sayısını hesaplıyor:

  • Sağ üst kısım eşit güçte bit sayısını sayar (sıfır ila 4)
  • Sol alttaki, tek bir güce (sıfır ila 4) sahip bit sayısını sayar

Bu sayıların farkı 0veya 3sayıları ile bölünebilirse 3. Sağ alt devre temel (her geçerli bir bileşimini haritalar 4,4, 4,1, 3,3, 3,0, 2, 2, 1, 1, 0, 0bir ya da da).

Ortadaki küçük daire, sayı 3'e bölünebilirse yanarsa açık olan bir LED'dir.


vay güzel / hızlı! ... plz kod veya satır içi bir bağlantı koymak ... ayrıca görselleştirme nasıl yaptığını ayrıntılı ...?
vzn

@vzn Görselleştirme logisim ile yapıldı . Elimle oluşturuldu, ancak genel algoritma bir programla da kolayca yapılabilir. Cevapta kısmen açıklanmıştır.
TimWolla
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.