Создание класса XOR для реализации полного сумматора

Я пробовал несколько разных подходов, включая создание отдельного класса NANDGate и использование NOR Gates, но я действительно не могу понять, где я ошибаюсь в своем подходе. Мое значение для вывода сумматора продолжает возвращаться как логическое значение, и результат переноса неверен для определенных входных данных, что, как я полагаю, связано с тем, что проблема заключается в моем классе XOR. Если кто-то может поставить меня в правильном направлении, это было бы очень признательно. Примечание: у меня очень мало опыта работы с Ruby, это мой второй раз, когда я программирую на нем

class Circuit
   # constructor method
   def initialize(in1, in2)
      @in1, @in2 = in1, in2
   end
end

class AndGate < Circuit

   def cir_func()
      (@in1 && @in2)
   end
end

class OrGate < Circuit

   def cir_func()
      (@in1 || @in2)
   end
end

class NotGate < Circuit
   def initialize(in1)
      @in1 = in1
   end

   def cir_func()
      (not @in1)
   end
end

class NandGate < Circuit

  def cir_func()
    (not (@in1_ && @in2_))
  end

end

class XOrGate < Circuit
  def initialize(in1, in2)
    @in1_ = in1
    @in2_ = in2
  end

  def cir_func()
    a0 = AndGate.new(@in1_, @in2_).cir_func()
    a0not = NotGate.new(a0).cir_func()
    a1 = AndGate.new(@in1_, a0not).cir_func()
    a1not = NotGate.new(a1).cir_func()
    a2 = AndGate.new(a0not, @in2_).cir_func()
    a2not = NotGate.new(a2).cir_func()
    o0 = AndGate.new(a1not, a2not).cir_func()
    o0not = NotGate.new(o0)
    return o0not.cir_func()
  end
end

class Mux_2to1 < Circuit

  def initialize(in1, in2, ctr1)
    @in1_ = in1
    @in2_ = in2
    @ctr1_ = ctr1
  end

  def cir_func()
    inv_ctr = NotGate.new(@ctr1_).cir_func()
    a0 = AndGate.new(@in1_, inv_ctr).cir_func()
    a1 = AndGate.new(@in2_, @ctr1_).cir_func()
    o0 = OrGate.new(a0, a1)
    return o0.cir_func()
  end
end

class Mux_4to1 < Circuit

  def initialize(in1, in2, in3, in4, ctr1, ctr2)
    @in1_ = in1
    @in2_ = in2
    @in3_ = in3
    @in4_ = in4
    @ctr1_ = ctr1
    @ctr2_ = ctr2
  end
  def cir_func()
    a0 = Mux_2to1.new(@in1_, @in2_, @ctr1_).cir_func()
    a1 = Mux_2to1.new(@in3_, @in4_, @ctr1_).cir_func()
    o0 = Mux_2to1.new(a0, a1, @ctr2_)
    return o0.cir_func()
  end
end

class FullAdder < Circuit

  def initialize(in1, in2, carryIn)
    @in1_ = in1
    @in2_ = in2
    @carry_ = carryIn
  end
  def cir_func()
    a0 = XOrGate.new(@in1_, @in2_).cir_func()
    o0 = XOrGate.new(a0, @carry_)
    a1 = AndGate.new(@in1_, @in2_).cir_func()
    a2 = AndGate.new(a0, @carry_).cir_func()
    o1 = OrGate.new(a1, a2)
    return o0.cir_func(), o1.cir_func()
  end
end


def Boolean(string)
  return true if string== true || string =~ (/(true|1)$/i)
  return false if string== false || string.nil? || string =~ (/(false|0)$/i)
  raise ArgumentError.new("invalid value for Boolean: \"#{string}\"")
end

puts "Please enter input 1 for adder:"
input_1 = gets()

puts "Please enter input 2 for adder:"
input_2 = gets()

puts "Please enter carry in for adder:"
carryin_ = gets()

x = FullAdder.new(input_1, input_2, carryin_)
output, carryOut = x.cir_func()
puts "The result for the adder is: #{output} and the carry out is: #{carryOut}"

person Jonathan Negron    schedule 09.05.2016    source источник
comment
Вам следует использовать побитовые операторы (&, |, ~) вместо логических операторов (&&, ||, !) или ключевых слов (and, or, not), если вы хотите возвращать целочисленные значения.   -  person Aetherus    schedule 09.05.2016
comment
Обратите внимание, что gets возвращает строку. Вероятно, вам придется преобразовать ввод в число/логическое значение (в вашем коде есть неиспользуемый метод Boolean)   -  person Stefan    schedule 09.05.2016


Ответы (2)


Убедитесь, что в следующий раз вы разбиваете свой код на более мелкие фрагменты и тестируете их изолированно. Это поможет вам определить проблему. Поскольку эти логические ворота вызывают воспоминания, я не мог с собой поделать, реализовал их самостоятельно и написал длинный ответ :-)

Я внес некоторые улучшения (я бы назвал это так :-)) в ваш код:

Поскольку у вас разное количество входных данных, я бы НЕ заставлял ваш родительский класс Circuit принимать определенное количество входных данных, а затем переопределять, чтобы изменить это число. Либо удалите родительский класс (мой предпочтительный способ), либо заставьте его принимать переменное количество входных данных. Это имеет некоторые преимущества, но также и недостатки (необходим доступ к входам как inputs[0] и т. д. Вы можете обойти это, предоставив средства доступа):

class Circuit
  def initialize(*inputs)
    @inputs = inputs
  end

  def call
    raise "Please implement in #{__FILE__}"
  end

  def inspect
    "#{self.class.name}: #{inputs.join(', ')} => #{call}"
  end

  private

  attr_reader :inputs
end

Поскольку вы выбрали родительский класс, я реализовал несколько примеров, используя эту технику:

class AndGate < Circuit
  def call
    inputs.inject do |memo, input|
      memo &&= input
      memo
    end
  end
end

class OrGate < Circuit

  def call
    inputs.inject do |memo, input|
      memo ||= input
      memo
    end
  end
end

class NotGate < Circuit
  def call
    !inputs[0]
  end
end

AndGate и OrGate поддерживают произвольное количество входов:

p AndGate.new(true, true, true).call # => true

Если вам это не нравится... тогда вы можете ограничить ввод...

Также обратите внимание, что я переименовал cir_func в call. Это по двум причинам:

  • Я не знаю, что означает cir
  • Мне не нравятся сокращенные имена методов (func)

но, конечно, вы можете изменить это, как вам нравится.

Теперь вы можете написать несколько тестов для проверки поведения:

require 'minitest/autorun'
class GateTest < Minitest::Test
  def assert_table(klass, table)
    table.each do |inputs, outputs|
      gate = klass.new(*inputs)
      assert_equal outputs, gate.call, "Expected #{klass} to convert #{inputs} to #{outputs}"
    end
  end
end

class AndGateTest < GateTest

  def test_gate
    table = {
      [false, false] => false,
      [false, true] => false,
      [true, false] => false,
      [true, true] => true
    }
    assert_table(AndGate, table)
  end

end
class OrGateTest < GateTest

  def test_gate
    table = {
      [false, false] => false,
      [false, true] => true,
      [true, false] => true,
      [true, true] => true
    }
    assert_table(OrGate, table)
  end

end

class NotGateTest < GateTest

  def test_gate
    table = {
      [false] => true,
      [true] => false,
    }
    assert_table(NotGate, table)
  end

end

Я выбрал тест суперкласса, который предоставляет вспомогательный метод для подтверждения того, что логическая таблица.

Имея базовые ворота, вы можете начать строить составные:

class NandGate < Circuit
 def call
   NotGate.new(
    AndGate.new(*inputs).call
  ).call
 end
end

И еще несколько сложных:

class XOrGate < Circuit
  def call
    OrGate.new(
      AndGate.new(
        NotGate.new(inputs[0]).call,
        inputs[1]
      ).call,
      AndGate.new(
        inputs[0],
        NotGate.new(inputs[1]).call
      ).call
    ).call
  end
end

И тесты для тех:

class NandGateTest < GateTest

  def test_gate
    table = {
      [false, false] => true,
      [false, true] => true,
      [true, false] => true,
      [true, true] => false
    }
    assert_table(NandGate, table)
  end

end

class XOrGateTest < GateTest

  def test_gate
    table = {
      [false, false] => false,
      [false, true] => true,
      [true, false] => true,
      [true, true] => false
    }
    assert_table(XOrGate, table)
  end

end

И, наконец, мы можем реализовать полный сумматор с его тестом:

class FullAdderGate < Circuit
  def call

    sum = XOrGate.new(
      inputs[2],
      XOrGate.new(
        inputs[0],
        inputs[1]
      ).call
    ).call

    carry = OrGate.new(
      AndGate.new(inputs[0], inputs[1]).call,
      AndGate.new(
        XOrGate.new(inputs[0], inputs[1]).call,
        inputs[2]
      ).call
    ).call

    [carry, sum]
  end

end

Вы могли бы уменьшить этот метод, назначая/повторно используя промежуточные результаты, но я не мог придумать умные имена, поэтому я этого не сделал :-)

class FullAdderGateTest < GateTest

  def test_gate
    table = {
      [false, false, false] => [false, false],
      [false, false, true] => [false, true],
      [false, true, false] => [false, true],
      [false, true, true] => [true, false],
      [true, false, false] => [false, true],
      [true, false, true] => [true, false],
      [true, true, false] => [true, false],
      [true, true, true] => [true, true],
    }
    assert_table(FullAdderGate, table)
  end

end

Внимание: для вашего кода вы хотите убедиться, что вы конвертируете ввод, который вы читаете через gets, в логические значения. У вас уже есть код с Boolean.

person Pascal    schedule 09.05.2016

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

#resulting values, do not set
sum0 = false
carry = false


#binary (set)
a = true
b = true

if a ^ b        #this is the equivalent of XOR
  sum0 = true
  carry = false
end

if a && b
  sum0 = false
  carry = true
end

#expand from here...
person Nick    schedule 18.09.2018