3으로 나눌 수있는 빌딩 회로


12

TCS 의 부울 회로 는 기본적으로 And, Or, Not 게이트로 구성된 DAG 이며 "기능 완결성"으로 알려진 모든 기능을 계산할 수 있습니다. 예를 들어 이것이 ALU 의 기본 원칙입니다 .

도전 과제 : 8 진 숫자를 3으로 나눌 수 있는지 확인하고 결과를 시각화하는 회로를 만듭니다 (예 : 어떤 종류의 그림).

유권자의 판단 기준은 회로를 생성하는 코드가 임의의 크기로 멋지게 일반화 되는지 여부와 알고리즘으로 생성 된 시각화가 콤팩트 / 밸런스이지만 여전히 사람이 읽을 수 있는지 (즉, 손 배열에 의한 시각화는 허용되지 않음)를 기반으로합니다. 즉, 시각화는 n = 8 전용이지만 코드는 모든 'n'에 이상적으로 작동합니다. 당첨 작은 최고 투표입니다.

다소 비슷한 질문 : NAND 논리 게이트를 사용하여 곱셈기 구축


2
훨씬 낫다. 그러나 "일반화"와 "미적"은 객관적이지 않습니다. 모든 질문에는 객관적인 승리 기준이 있어야합니다. 이러한 특성을 적용하려면 인기 경연 대회를 사용하십시오. 가장 짧은 코드를 원하면 code-golf를 사용하십시오. 이 두 가지를 조합하려면 code-challenge를 사용하되 수식을 지정하십시오. 예를 들어 1.25 * votes-0.25 * length이 질문 에서처럼
Level River St

ok는 당신이 요구하는 chgs를 만들었습니다. 피드백을위한 thx.
vzn

Oghh, 모든 최적화가 가장 짧은 답변을 제공 한 후에 컴파일 된 VHDL 또는 Verilog를 추측합니다. 나중에 다시 시도하겠습니다.
Kirill Kulakov

1
더 나은 우승 기준은 게이트 골프입니다.
TheDoctor

@의사 ??? 무엇 gate-golf입니까? 해당 태그가 존재하지 않습니다. 참가자 참고 사항 : 사용중인 언어 / 시각화 도구를 설명하십시오. 다른 사람이 PLZ 의견을 입력하려는 경우. 그렇지 않으면 승자 톤을 수락합니다. 지금까지 응답자에게 크게 감사드립니다. 예상보다 'BTE'가 더 우수했습니다!
vzn

답변:


7

수 모듈로 3을 계산하는 회로

그래프는 각 레벨 i에서 3 개의 부울 값을 유지합니다. 이들은 숫자의 고차 i 비트가 0, 1 또는 2 mod 3과 같다는 사실을 나타냅니다. 각 레벨에서 이전 3 비트와 다음 입력 비트를 기준으로 다음 3 비트를 계산합니다.

그래프를 생성 한 파이썬 코드는 다음과 같습니다. 다른 비트 수를 얻으려면 N을 변경하고 다른 계수를 얻으려면 K를 변경하십시오. 을 통해 파이썬 프로그램의 출력을 실행하여 이미지를 생성하십시오.

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 도사용했습니다... 작은 퀴즈, 다이어그램에 사용되지 않은 AND / OR이 있습니다. 또한 다른 색상으로 입력 비트를 강조 표시하여 위치를 표시 할 수도 있습니다.
vzn

@ vzn : 좋아, 고정.
Keith Randall

12

깊이 : 7 (대수), 18x AND, 6x OR, 7x XOR, 31 게이트 (선형)

기본 4, 모듈로 3의 숫자 합계를 계산하겠습니다.

계층 구조가 명확하게 보이는 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

지금 영어로 :

숫자에 두 개 이상의 비트가있는 동안 두 개의 가장 낮은 비트 쌍을 취하여 모듈로 3을 합한 다음 결과를 숫자 뒤에 더한 다음 마지막 쌍이 0 인 모듈로 3이면 반환합니다. 숫자의 비트 수, 상단에 여분의 0 비트를 추가 한 다음 일정한 값의 전파로 연마하십시오.

앞면 대신 뒷면에 추가하면 추가 트리가 연결된 목록이 아닌 균형 잡힌 트리가됩니다. 따라서 비트 수의 로그 깊이가 보장됩니다. 5 개의 게이트와 페어 상쇄를위한 3 개의 레벨, 끝에 추가 게이트가 있습니다.

물론, 대략적인 평면성이 필요한 경우 수정하지 않은 맨 위 쌍을 맨 앞으로 감싸지 않고 다음 레이어로 전달하십시오. 그러나 (의사 코드에서도) 구현되는 것보다 쉽습니다. 그러나 숫자의 비트 수가 2의 거듭 제곱 인 경우 (2014 년 3 월 현재 모든 최신 컴퓨터 시스템에서와 동일) 단독 쌍은 발생하지 않습니다.

레이아웃 러가 위치를 유지하고 경로 길이 최소화를 수행하는 경우 회로를 읽을 수 있어야합니다.

이 루비 코드는 임의의 수의 비트 (1 개)에 대한 회로도를 생성합니다. 인쇄하려면 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 비트에 대한 출력을 만들라는 요청을 받으면 레이아웃 작성자가 이것을 생성합니다. 물론 매우 넓은 입력에 대해서는 매우 컴팩트하지 않습니다.

낭비되는 공간이 많은 13 층의 괴물


지금까지 정말 훌륭하고 최상의 회로 / 레이아웃으로 보입니다. 코드는 어떤 언어입니까? 어떤 레이아웃 러를 사용 했습니까? 레이아웃은 알고리즘이 요구되었고, 언급되지 않는 한 알고리즘이 사용되지 않았다고 가정해야합니다 (손 레이아웃).
vzn

@vzn 레이아웃 러도 구현해야 했습니까? 나는 다이어그램을 수동으로 그릴 수 있다는 의미로 제한을 이해했지만 가독성은 다이어그램을 그리는 방식에 의존해서는 안됩니다. TimWolla의 회로는 확실히 수동으로 생성됩니다. 의사 코드는 주로 Javascripty 객체가 추가 된 Haskell을 기반으로합니다.
John Dvorak

알고리즘 적으로 생성 된 시각화 는 기본적으로 알고리즘 레이아웃 을 의미 하지만 이제는 모호하게 해석 될 수 있음을 인정합니다. 선명도가 부족하여 죄송합니다. 손 레이아웃과 거의 비슷한 결과를 얻을 수있는 자동화 된 레이아웃 도구를 알고 있습니까?
vzn

불행하게도. yEd에는 훌륭한 레이아웃 기능이 있지만 방향을 무시합니다. 나는 점에 익숙하지도 않았고 그 출력이 정확하게 훌륭하다는 것을 알았습니다. 나는이 의사 코드를 Ruby (쉽게)로 변환하고 logisim 회로를 내보내는 내 자신의 특수한 레이아웃 (너무 어렵지는 않지만 복잡한)을 작성할 수 있다고 생각합니다 (XML 일뿐 아니라 너무 쉽게 압축되지도 않습니다). 나는 (내가 원하고) 그것을 별도의 답변으로 게시해야합니까? 또한 손으로 디자인 한 것으로 간주됩니까?
John Dvorak

모든 좋은 답변이지만, 지금까지 가장
Digital Trauma

5

2 × 24 NOT, 2 × 10 + 5 AND, 2 × 2 + 5 OR, 2 × 2 NOR

이것은 완전히 확장되지 않습니다. 전혀 그렇지 않습니다. 어쩌면 나는 그것을 개선하려고 노력할 것입니다.

나는 이것을 30까지의 숫자로 테스트했으며 정상적으로 작동했습니다.

이 두 개의 큰 회로는 활성 입력 수를 계산합니다.

  • 오른쪽 상단은 짝수의 전력 (0 ~ 4)으로 비트 수를 계산합니다.
  • 왼쪽 하단은 홀수 비트 수 (0 ~ 4)를 계산합니다.

해당 숫자의 차이가 0이거나 3로 나눌 수있는 경우 3. 우하 회로는 기본적으로 (각각의 유효한 조합 매핑 4,4, 4,1, 3,3, 3,0, 2, 2, 1, 1, 0, 0는 OR로).

가운데 작은 원은 숫자를 3으로 나눌 수 있으면 켜지고 그렇지 않으면 꺼집니다.


와우 / 빨리! ... PLZ는 코드에 링크를 삽입하거나 인라인합니다 ... 또한 시각화 방법을 자세히 설명합니다 ...?
vzn

@vzn logisim으로 시각화가 이루어 졌습니다 . 그것은 내 손으로 만들어졌지만 일반적인 알고리즘은 프로그램으로 쉽게 수행 할 수 있습니다. 답에 부분적으로 설명되어 있습니다.
TimWolla
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.