строительная схема делимости на 3


12

Логический контур в ТКС в основном DAG , состоящий из и, или, не ворота, а то , что известно «функциональная полнота» они могут вычислить все возможные функции. Например, это основной принцип в АЛУ .

Задача: создать схему, чтобы определить, делится ли 8-значное двоичное число на 3, и каким-то образом визуализировать ваш результат (например, на каком-то изображении)

Критерии оценки для избирателей основаны на том, хорошо ли обобщает код для генерации схемы числа произвольного размера, и является ли алгоритмически созданная визуализация компактной / сбалансированной, но все же удобочитаемой для человека (то есть визуализация с помощью ручной компоновки не допускается). то есть визуализация только для n = 8, но код в идеале будет работать для всех n. Победившая заявка только что проголосовала.

Несколько похожий вопрос: постройте умножающую машину, используя логические вентили NAND


2
Намного лучше. Однако «обобщение» и «эстетика» не являются объективными. Все вопросы должны иметь объективный критерий победы. Если вы хотите применить эти характеристики, используйте популярность-конкурс. Если вы хотите самый короткий код, используйте код-гольф. Если вы хотите создать комбинацию из двух, используйте вызов кода, но укажите формулу. Например, 1,25 * голосов - 0,25 * длины, как этот вопрос: codegolf.stackexchange.com/questions/23581/eiffel-tower-in-3d/…
Уровень Река Сент

хорошо сделал те Chgs, которые вы просите. Спасибо за отзыв.
14:00

Ох, я думаю, скомпилированный VHDL или Verilog после всех его оптимизаций должен дать кратчайший ответ. Я попробую это позже.
Кирилл Кулаков


@Доктор ??? что такое gate-golf? этот тег не существует. Примечание для участников: пожалуйста, укажите, какой язык / инструмент визуализации вы используете. если кто-то хочет ввести комментарий плз. в противном случае примет победитель tonite. Спасибо большое респондентам, что «БТЭ» прошло лучше, чем ожидалось!
vzn

Ответы:


7

схема для вычисления числа по модулю 3

График поддерживает 3 логических значения на каждом уровне i. Они представляют тот факт, что старшие биты i числа равны 0, 1 или 2 mod 3. На каждом уровне мы вычисляем следующие три бита на основе предыдущих трех бит и следующего входного бита.

Вот код Python, который сгенерировал график. Просто измените 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 ... крошечный обман, на диаграмме есть неиспользуемые AND / OR. также предложите, возможно, выделить входные биты другим цветом, чтобы показать их местоположение
vzn

@vzn: Хорошо, исправлено.
Кит Рэндалл

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

сейчас на английском:

В то время как в числе более двух битов, возьмите две младшие пары битов и сложите их по модулю 3, затем добавьте результат к обратной части числа, а затем верните, если последняя пара равна нулю по модулю 3. Если есть нечетное число количество битов в числе, добавьте дополнительный нулевой бит к вершине, затем отполируйте с постоянным значением распространения.

Добавление сзади, а не вперед гарантирует, что дерево дополнений будет сбалансированным, а не связанным списком. Это, в свою очередь, обеспечивает логарифмическую глубину в количестве битов: пять вентилей и три уровня для отмены пары, и дополнительный вентиль в конце.

Конечно, если требуется приблизительная планарность, передайте верхнюю пару без изменений на следующий слой, а не оборачивайте ее спереди. Однако это легче сказать, чем реализовать (даже в псевдокоде). Если число битов в числе является степенью двойки (как в любой современной компьютерной системе по состоянию на март 2014 года), то одиночных пар не будет, однако.

Если планировщик сохраняет локальность / выполняет минимизацию длины маршрута, он должен сохранять читаемость схемы.

Этот код 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 бит, мой Layouter генерирует это. По общему признанию, это не очень компактно для очень широких входов:

13-слойное чудовище с большим количеством потерянного пространства


выглядит действительно здорово и лучшая схема / макет до сих пор. на каком языке код? какой Layouter вы использовали, если таковые имеются? Layouter был запрошен, чтобы быть алгоритмом, и должен предполагать, что алгоритм не использовался (раскладка руки), если не указано ...
vzn

@vzn также должен быть реализован макет? Я понял, что это ограничение означает, что мы можем нарисовать диаграмму вручную, но удобочитаемость не должна зависеть от того, как она нарисована. Схема TimWolla определенно создана вручную. Псевдокод в основном основан на Haskell с добавленными объектами Javascripty.
Джон Дворжак

Алгоритмически созданная визуализация должна была означать в основном алгоритмический макет, но теперь следует признать, что это можно интерпретировать неоднозначно. извините за отсутствие кристальной ясности. Знаете ли вы о каком-либо автоматизированном макете, который может получить результаты, почти такие же, как у вашей руки?
ВЗН

К сожалению нет. YEd имеет отличные Layouters, но он игнорирует ориентацию. Я никогда не знакомился с точкой, и я не нахожу ее вывод очень хорошим. Я думаю, я мог бы перевести этот псевдокод на Ruby (просто) и написать свой собственный специализированный Layouter (не слишком сложный, но сложный), который экспортировал бы схему logisim (это всего лишь XML, и он даже не был сжат, так что это довольно просто). Должен ли я (я хочу), и я должен опубликовать это как отдельный ответ? Кроме того, это считается ручной работы?
Джон Дворак

Все хорошие ответы, но это выглядит как самый элегантный на сегодняшний день
Digital Trauma

5

2 × 24 НЕ, 2 × 10 + 5 И, 2 × 2 + 5 ИЛИ, 2 × 2 НОР

Это полностью не масштабируется. Вроде нет совсем. Возможно я постараюсь улучшить это.

Я проверил это для чисел до 30, и это работало отлично.

Эти две большие цепи подсчитывают количество активных входов:

  • Верхний правый отсчитывает количество бит с четной степенью (от 0 до 4)
  • Нижний левый считает количество бит с нечетной степенью (от 0 до 4)

Если разница этих чисел 0или 3число делится на 3. В нижнем правом углу контура в основном отображает каждую допустимая комбинация ( 4,4, 4,1, 3,3, 3,0, 2, 2, 1, 1, 0, 0) или в.

Маленький кружочек в середине - это светодиод, который горит, если число делится на 3, и выключается в противном случае.


вау красиво / быстро! ... PLZ поставить ссылку на код или встроить его ... также подробно, как вы сделали визуализацию ...?
14:00

@vzn Визуализация была сделана с помощью logisim . Он был построен моей рукой, но общий алгоритм можно легко сделать с помощью программы. Это частично объясняется в ответе.
TimWolla
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.