วงจรอาคารสำหรับการหาร 3


12

วงจรบูลใน TCS เป็นพื้นDAGประกอบด้วยและหรือไม่ประตูเมืองและสิ่งที่เป็นที่รู้จักกันคือ "การทำงานครบถ้วน" พวกเขาสามารถคำนวณฟังก์ชั่นเป็นไปได้ทั้งหมด เช่นนี้เป็นหลักการพื้นฐานในALU

ถาม: สร้างวงจรเพื่อตรวจสอบว่าตัวเลข 8 หลักสองหลักหารด้วย 3 ได้หรือไม่และเห็นภาพผลลัพธ์ของคุณ (เช่นรูปภาพบางประเภท)

เกณฑ์การตัดสินคะแนนเสียงขึ้นอยู่กับว่าเป็นรหัสในการสร้างวงจรgeneralizesอย่างกับตัวเลขขนาดโดยพลการและไม่ว่าการสร้างภาพอัลกอริทึมที่สร้างขึ้นมีขนาดเล็ก / สมดุล แต่ยังคงมนุษย์สามารถอ่านได้ (เช่นการสร้างภาพโดยการจัดมือไม่ได้รับอนุญาต) นั่นคือการสร้างภาพข้อมูลสำหรับ n = 8 เท่านั้น แต่รหัสจะทำงานได้ดีสำหรับทุกคน 'n' ผลงานที่ชนะเลิศได้รับการโหวตสูงสุด

คำถามที่คล้ายกัน: สร้างเครื่องคูณโดยใช้ประตูตรรกะ NAND


2
ดีกว่ามาก อย่างไรก็ตาม "พูดคุย" และ "สุนทรียะ" นั้นไม่ได้มีวัตถุประสงค์ คำถามทั้งหมดจะต้องมีเกณฑ์การชนะอย่างมีวัตถุประสงค์ หากคุณต้องการใช้คุณสมบัติเหล่านั้นให้ใช้การประกวดความนิยม ถ้าคุณต้องการรหัสที่สั้นที่สุดให้ใช้ code-golf หากคุณต้องการที่จะรวมกันของทั้งสองใช้รหัสท้าทาย แต่ระบุสูตร ตัวอย่างเช่น 1.25 * votes - ความยาว 0.25 * ตามที่คำถามนี้ทำ: codegolf.stackexchange.com/questions/23581/eiffel-tower-in-3d/…
Level River St

ตกลงทำให้ chgs ที่คุณขอ ขอบคุณสำหรับคำติชม
vzn

อืมฉันเดาว่า VHDL หรือ Verilog ที่คอมไพล์แล้วหลังจากการปรับแต่งทั้งหมดควรให้คำตอบที่สั้นที่สุด ฉันจะลองอีกครั้ง
Kirill Kulakov

1
เกณฑ์การชนะที่ดีกว่าคือเกทกอล์ฟ
TheDoctor

@แพทย์ ??? คือgate-golfอะไร แท็กนั้นไม่มีอยู่ หมายเหตุถึงผู้เข้าร่วม: โปรดระบุเครื่องมือภาษา / การสร้างภาพข้อมูลที่คุณใช้ ถ้าใครต้องการใส่ความคิดเห็นนะ มิฉะนั้นจะยอมรับผู้ชนะ tonite ขอบคุณมากสำหรับผู้ตอบแบบสอบถามจนถึงตอนนี้สิ่งนี้ "BTE" ดีกว่าที่คาดไว้!
vzn

คำตอบ:


7

วงจรคำนวณจำนวนโมดูโล 3

กราฟเก็บรักษา 3 booleans ในแต่ละระดับ i พวกเขาเป็นตัวแทนของความจริงที่ว่าบิตสูงลำดับที่ฉันของจำนวนเท่ากับ 0, 1, หรือ 2 mod 3 ในแต่ละระดับเราคำนวณสามบิตถัดไปขึ้นอยู่กับสามบิตก่อนหน้าและบิตถัดไป

นี่คือรหัสไพ ธ อนที่สร้างกราฟ เพียงแค่เปลี่ยน N เพื่อรับจำนวนบิตที่แตกต่างกันหรือ K เพื่อรับมอดุลัสที่แตกต่างกัน รันเอาต์พุตของโปรแกรม python ผ่านจุดเพื่อสร้างภาพ

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 '}'

ที่ดี! ได้ใช้ graphvizด้วย ... เล่นลิ้นเล็ก ๆ มี ANDs / ORs ที่ไม่ได้ใช้ในแผนภาพ อาจแนะนำให้ไฮไลต์บิตอินพุตในสีที่แตกต่างกันเพื่อแสดงตำแหน่งของมัน
vzn

@vzn: ตกลงแก้ไขแล้ว
Keith Randall

12

ความลึก: 7 (ลอการิทึม), 18x AND, 6x OR, 7x XOR, 31 ประตู (เชิงเส้น)

ขอผมคำนวณผลรวมหลักในฐานสี่, โมดูโลสาม:

วงจร 7 ชั้นพร้อมโครงสร้างลำดับชั้นที่มองเห็นได้ชัดเจน

วาดวงจรในLogisim

การวางนัยทั่วไปอย่างเป็นทางการ (หวังว่าจะอ่านได้บ้าง):

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

ตอนนี้เป็นภาษาอังกฤษ:

ในขณะที่มีมากกว่าสองบิตในจำนวนใช้สองคู่ต่ำสุดของบิตและผลรวม modulo 3 จากนั้นผนวกผลลัพธ์ที่ด้านหลังของตัวเลขแล้วส่งกลับถ้าคู่สุดท้ายเป็นศูนย์โมดูโล 3 ถ้ามีคี่ จำนวนบิตในจำนวนเพิ่มบิตศูนย์พิเศษที่ด้านบนจากนั้นขัดด้วยการแพร่กระจายค่าคงที่

ต่อท้ายด้านหลังแทนที่จะเป็นด้านหน้าทำให้มั่นใจได้ว่าการเพิ่มทรีนั้นเป็นต้นไม้ที่สมดุลแทนที่จะเป็นรายการที่เชื่อมโยง ในทางกลับกันทำให้มั่นใจได้ว่าความลึกลอการิทึมในจำนวนบิต: ห้าประตูและสามระดับสำหรับการยกเลิกคู่และประตูพิเศษที่ปลาย

แน่นอนว่าถ้าต้องการระนาบโดยประมาณให้ส่งผ่านคู่บนสุดที่ไม่ได้แก้ไขไปยังเลเยอร์ถัดไปแทนที่จะห่อไว้ด้านหน้า สิ่งนี้พูดง่ายกว่าการนำไปใช้ (แม้ใน pseudocode) หากจำนวนบิตในตัวเลขเป็นกำลังสอง (ตามจริงในระบบคอมพิวเตอร์สมัยใหม่ใด ๆ ณ เดือนมีนาคม 2014) จะไม่มีการจับคู่คนเดียว

ถ้า layouter รักษาตำแหน่ง / ทำการลดความยาวของเส้นทางมันควรทำให้วงจรอ่านได้

รหัส Ruby นี้จะสร้างแผนภาพวงจรสำหรับจำนวนบิตใด ๆ (แม้แต่หนึ่ง) หากต้องการพิมพ์ให้เปิดใน Logisim และส่งออกเป็นรูปภาพ:

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"

ในที่สุดเมื่อถูกขอให้สร้างเอาต์พุตสำหรับ 32 บิต lay lay ของฉันจะสร้างสิ่งนี้ เป็นที่ยอมรับว่ามีขนาดเล็กมากสำหรับอินพุตที่กว้างมาก:

ความน่าประหลาดใจ 13 ชั้นพร้อมพื้นที่ว่างเปล่ามากมาย


ดูดีจริงๆ & ดีที่สุดวงจร / เลย์เอาต์ มีรหัสภาษาอะไร คุณใช้ชุดนอนแบบใด layouter ก็ขอเป็นอัลกอริทึมและต้องถือว่าขั้นตอนวิธีการที่ไม่ได้ใช้ (รูปแบบมือ) ยกเว้นที่ระบุไว้ ...
vzn

@vzn ต้องใช้งาน layouter ด้วยหรือไม่ ฉันเข้าใจว่าข้อ จำกัด ตามความหมายที่ว่าเราสามารถวาดไดอะแกรมด้วยตนเอง แต่การอ่านจะต้องไม่ขึ้นอยู่กับวิธีวาดไดอะแกรม วงจรของ TimWolla นั้นทำด้วยมืออย่างแน่นอน รหัสหลอกส่วนใหญ่จะขึ้นอยู่กับ Haskell ด้วยการเพิ่มวัตถุ Javascripty
John Dvorak

การสร้างภาพสร้างอัลกอริทึมก็หมายความว่าจะหมายถึงพื้นlayouter อัลกอริทึมแต่ตอนนี้ยอมรับว่าอาจจะตีความเลศนัย ขอโทษที่ขาดความชัดเจนคริสตัล คุณรู้เรื่องการจัดเรียงอัตโนมัติใด ๆ ที่สามารถให้ผลลัพธ์ที่ใกล้เคียงกับรูปแบบมือของคุณหรือไม่
vzn

น่าเสียดายที่ไม่มี yEd มี layouters ที่ดี แต่มันละเว้นการวางแนว ฉันไม่เคยคุ้นเคยกับจุดหรือหาผลลัพธ์ที่ดี ฉันเดาว่าฉันสามารถแปล pseudocode นี้เป็น Ruby (ง่าย) และเขียน layouter เฉพาะของฉันเอง (ไม่ยากเกินไป แต่ซับซ้อน) ที่จะส่งออกวงจร logisim (เป็นเพียง XML และไม่แม้แต่ gzipped จึงค่อนข้างง่าย) ฉันควร (ฉันต้องการ) และฉันควรโพสต์สิ่งนั้นเป็นคำตอบแยกต่างหากหรือไม่ นอกจากนี้สิ่งนั้นจะนับว่าถูกออกแบบด้วยมือหรือไม่?
John Dvorak

คำตอบที่ดีทั้งหมด แต่ดูเหมือนว่าจะดูดีที่สุดเท่าที่เคยมีมา
Digital Trauma

5

2 × 24 ไม่ 2 × 10 + 5 และ 2 × 2 + 5 หรือ 2 × 2 NOR

ทั้งหมดนี้ไม่ได้ปรับขนาด ไม่ชอบเลย บางทีฉันจะพยายามปรับปรุงมัน

ฉันทำการทดสอบเพื่อหาตัวเลขมากถึง 30 และใช้งานได้ดี

ทั้งสองวงจรใหญ่กำลังนับจำนวนอินพุตที่ใช้งานอยู่:

  • มุมขวาบนนับจำนวนบิตด้วยกำลังคู่ (ศูนย์ถึง 4)
  • ด้านซ้ายล่างนับจำนวนบิตด้วยพลังคี่ (ศูนย์ถึง 4)

หากความแตกต่างของตัวเลขเหล่านั้นเป็น0หรือ3หารด้วย3จำนวน วงจรขวาล่างพื้นแผนที่แต่ละชุดที่ถูกต้อง ( 4,4, 4,1, 3,3, 3,0, 2, 2, 1, 1, 0, 0) ลงหรือ

วงกลมเล็ก ๆ ที่อยู่ตรงกลางคือ LED ที่เปิดอยู่ถ้าจำนวนหารด้วย 3 และปิดเป็นอย่างอื่น


ว้าวดี / เร็ว! ... โปรดใส่ลิงค์ไปยังโค้ดหรืออินไลน์ ... และให้รายละเอียดวิธีการสร้างภาพข้อมูล ...
vzn

@vzn สร้างภาพได้ถูกทำให้มีLogisim มันถูกสร้างขึ้นด้วยมือของฉัน แต่อัลกอริทึมทั่วไปสามารถทำได้อย่างง่ายดายด้วยโปรแกรมเช่นกัน มีการอธิบายบางส่วนในคำตอบ
TimWolla
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.