Circuito lógico digital - pregunta de examen

14

Tengo una pregunta del examen que no pude resolver:

Necesito construir un circuito lógico digital que reciba un número de 4 bits y devolver truesi el número es 0, 7o 14. Solo tengo una XORpuerta (2 entradas), una NOR(3 entradas), una NAND(2 entradas) y un decodificador de 3 a 8.

Creo que esa pregunta no tiene solución, no encontré ninguna combinación que pueda hacer eso. ¿Alguna idea de cómo solucionarlo?

nrofis
fuente
1
Como pista: dados 4 bits y un decodificador 3-8, debe tratar uno de los bits de manera diferente.
Brian Drummond
2
@BrianDrummond, pero eso ya lo sé, y todavía no logré resolverlo. Cada solución que probé siente que le falta una puerta OR. No puedo encontrado tales combinación con las puertas dado que puede resolver el problema ... Tenga en cuenta que sólo tengo una puerta según el tipo de ...
nrofis
3
@BrianDrummond: si publica una descripción de la solución que cree que existe, podríamos verificarla. Es difícil decir que no existe una solución, pero es fácil verificar si una solución es válida.
pasaba por aqui
2
@Ido Kessler ... Su solución me intrigó y si su prueba es correcta, lamento que la haya eliminado. Nadie hasta ahora parece tener una solución. Quizás si incluye una descripción de su algoritmo, mejoraría la respuesta. ¿Qué tan seguro está de que es correcto y libre de errores?
Tut
3
@jalalipop, lo hice ayer. Ido Kessler y pasaba por aqui estaban en lo cierto, mi profesor dijo que la cuestión estaba mal y el NAND debe ser NOR ....
nrofis

Respuestas:

24

Escribí un algoritmo en C # que intenta todas las combinaciones posibles de esos Nor 3->1 Xor 2->1 Nand 2->1y Decoder 3->8.

Después de ejecutarlo durante 7½ millones de años 2 horas, devolvió 42 Falso. Creo que esto prueba que la pregunta no tiene respuesta ya que este algoritmo verifica todas las combinaciones posibles. :)

Me pidieron que lo describiera, así que la siguiente parte es una explicación de las partes del código, parte por parte. TL; DR : puede saltar al código hacia abajo al final :)


Hablemos de las líneas de entrada, tienen 0 o 1 estados y para cada una de las posibles entradas (0 a 15) tienen diferentes valores:

para la primera línea se ve así: 0 1 0 1 0 1 ... La segunda es: 0 0 1 1 0 0 1 1 ... la tercera: 0 0 0 0 1 1 1 1 .... como binaria contando ... tienes la idea: P

Entonces creé un objeto que representa cada línea en cada uno de sus estados:

class BitLine{
    bool[] IsActiveWhenInputIs = new bool[16];
}

Como dice bitLine.IsActiveWhenInputIs [5] devuelve si la línea estaba activa cuando la entrada era 5.

Este es un código que crea las líneas de entrada por completo:

var bitLineList = new BitLine[6]; // initialize new array of bitLines
for (int i = 0; i < 6; i++) bitLineList [i] = new BitLine(); // initialize each bitLine
for (int i = 0; i < 16; i++)
{
    for (int j = 0; j < 4; j++)
    {
        int checker = 1 << j; // check whether the j-th bit is activated in the binary representation of the number.
        bitLineList[j].IsActiveWhenInputIs[i] = ((checker & i) != 0); // if it's active, the AND result will be none zero, and so the return value will be true - which is what we need :D
    }
}

También crearemos líneas de bits "siempre verdaderas" y "siempre falsas" para proporcionar una entrada constante "0" o una entrada "1".

for (int i = 0; i < 16; i++){
    bitLineList[4].IsActiveWhenInputIs[i] = false;
    bitLineList[5].IsActiveWhenInputIs[i] = true;
}

Ahora, si se da cuenta, lo que estamos buscando es en realidad una línea de bits específica, una que sea verdadera cuando la entrada es 0, 7, 14. Represéntelo en nuestra clase:

var neededBitLine = new BitLine();
for (int i = 0; i < 16; i++){
    neededBitLine.IsActiveWhenInputIs[i] = ((i % 7) == 0); // be true for any number that is devideble by 7 (0,7,14)
}

Esto hizo las cosas realmente simples: lo que realmente estamos buscando es una forma de "falsificar" esta necesaria BitLine desde la línea de bits de entrada (así es como represento a mi programa lo que quiero que sea mi salida).

Ahora, así es como vamos en: cada vez que utilizamos algún elemento lógico en nuestras líneas de bits como Xor, Nor, Nando incluso el Decoder, en realidad estamos creando una nueva línea de bits \ T. ¡Conocemos el valor de cada una de las líneas en cada entrada posible de 0 a 15, por lo que también podemos calcular el nuevo valor de bitLine \ s en cada entrada posible!

Nand Nor y Xor son sencillos:

void Xor(BitLine b1, BitLine b2, BitLine outputBitLine)
{
    for (var i = 0; i < 16; i++)
    {
        outputBitLine.IsActiveWhenInputIs[i] = b1.IsActiveWhenInputIs[i] != b2.IsActiveWhenInputIs[i];
    }
}

void Nand(BitLine b1, BitLine b2, BitLine outputBitLine)
{
    for (var i = 0; i < 16; i++)
    {
        outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] && b2.IsActiveWhenInputIs[i]);
    }
}

void Nor(BitLine b1, BitLine b2, BitLine b3, BitLine outputBitLine)
{
    for (var i = 0; i < 16; i++)
    {
        outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] || b2.IsActiveWhenInputIs[i] || b3.IsActiveWhenInputIs[i]);
    }
}

Para cada entrada posible, representa cómo actuará la nueva BitLine.

Manejar el decodificador es un poco complicado, pero la idea es "si los bits en la entrada representan el número x en binario, entonces la línea de bits de salida x-ésima será verdadera, mientras que todas las demás serán falsas. A diferencia del otro función, esta obtiene una matriz de línea de bits y agrega 8 nuevas líneas de bits a la matriz.

void Decoder(BitLine b1, BitLine b2, BitLine b3, List<BitLine> lines, int listOriginalLength)
{
    for (int optionNumber = 0; optionNumber < 8; optionNumber++)
    {
        for (var i = 0; i < 16; i++)
        {
            int sum = 0;
            if (b1.IsActiveWhenInputIs[i]) sum += 4;
            if (b2.IsActiveWhenInputIs[i]) sum += 2;
            if (b3.IsActiveWhenInputIs[i]) sum += 1;

            lines[listOriginalLength+optionNumber].IsActiveWhenInputIs[i] = (sum == optionNumber);
        }
    }
}

Ahora tenemos todos nuestros elementos básicos, así que hablemos sobre el algoritmo:

Vamos a hacer un algoritmo recursivo, en cada profundidad intentará usar otros elementos (ni \ nand \ xor \ decoder) en las líneas de bits disponibles actualmente, y luego establecerá el elemento como inutilizable para la siguiente profundidad recursiva. Cada vez que lleguemos al fondo y no tengamos más elementos para usar, verificaremos si tenemos una línea de bits que es lo que estábamos buscando.

Este código verifica en cualquier momento si el grupo actual de líneas contiene la línea que estamos buscando:

bool CheckIfSolutionExist(List<BitLine> lines, int linesLength BitLine neededLine)
{
    for(int i = 0; i<linesLength; i++){
         if (lines[i].CheckEquals(neededLine))
        {
            return true;
        }

    }
    return false;
}

Esta es la función que utiliza para verificar si dos líneas son iguales:

bool CheckEquals(BitLine other)
{
    for (var i = 0; i < 16; i++)
    {
        if (this.IsActiveWhenInputIs[i] != other.IsActiveWhenInputIs[i])
        {
            return false;
        }
    }
    return true;
}

Ok, ahora para la parte principal, este es el algoritmo principal:

bool Solve(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
    if ((!nand) && (!nor) && (!xor) && (!decoder))
    {
        return CheckIfSolutionExist(lines, listLength, neededLine);
    }
    else
    {
        if (HandleNand(lines, nand, nor, xor, decoder, neededLine,listLength))
        {
            return true;
        }
        if (HandleNor(lines, nand, nor, xor, decoder, neededLine,listLength))
        {
            return true;
        }
        if (HandleXor(lines, nand, nor, xor, decoder, neededLine,listLength))
        {
            return true;
        }
        if (HandleDecoder(lines, nand, nor, xor, decoder, neededLine,listLength))
        {
            return true;
        }
        return false;
    }
}

Esta función recibe una lista de las líneas de bits disponibles, la longitud de la lista, un valor booleano que representa si cada elemento está disponible actualmente (xor / nor / nand / decoder) y una línea de bits que representa la línea de bits que estamos buscando.

En cada etapa, verifica si tenemos más elementos para usar, si no, verifica si archivamos nuestra línea de bits necesaria.

Si todavía tenemos más elementos, entonces para cada elemento llama a una función que se supone que maneja la creación de nuevas BitLines usando esos elementos y luego llama a la siguiente profundidad recursiva.

Las siguientes funciones del controlador son bastante sencillas, se pueden traducir a "elegir 2 \ 3 de las líneas de bits disponibles y combinarlas con el elemento relevante. Luego llame a la siguiente profundidad de la recursión, solo que esta vez no contendrá este elemento ".

esas son las funciones:

bool HandleNand(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
    if (nand)
    {
        for (int i = 0; i < listLength; i++)
        {
            for (int j = i; j < listLength; j++)
            {
                BitLine.Nand(lines[i], lines[j],lines[listLength]);
                if (Solve(lines,listLength+1, false, nor, xor, decoder, neededLine))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

bool HandleXor(List<BitLine> lines,  int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
    if (xor)
    {
        for (int i = 0; i < listLength; i++)
        {
            for (int j = i; j < listLength; j++)
            {
                BitLine.Xor(lines[i], lines[j],lines[listLength]);
                if (Solve(lines,listLength+1, nand, nor, false, decoder, neededLine))
                {
                    return true;
                }

            }
        }
    }
    return false;
}

bool HandleNor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
    if (nor)
    {
        for (int i = 0; i < listLength; i++)
        {
            for (int j = i; j < listLength; j++)
            {
                for (int k = j; k < listLength; k++)
                {
                    BitLine.Nor(lines[i], lines[j], lines[k],lines[listLength]);
                    if (Solve(lines,listLength+1, nand, false, xor, decoder, neededLine))
                    {
                        return true;
                    }

                }
            }
        }
    }
    return false;
}

bool HandleDecoder(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
{
    if (decoder)
    {
        for (int i = 0; i < listLength; i++)
        {
            for (int j = i; j < listLength; j++)
            {
                for (int k = j; k < listLength; k++)
                {
                    BitLine.Decoder(lines[i], lines[j], lines[k],lines,listLength);
                    if (Solve(lines,listLength+8, nand, nor, xor, false, neededLine))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

Y esto es todo, solo llamamos a esta función con la línea necesaria que estamos buscando, y verifica todas las combinaciones posibles de las partes eléctricas para verificar si es posible combinarlas de tal manera que al final una sola línea sea salida con los valores necesarios.

* observe que uso la misma lista todo el tiempo, por lo que no necesitaré crear nuevas instancias de bitlines todo el tiempo. Le doy un búfer de 200 por ese motivo.


Este es el programa completo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    public class BitLine
    {
        public bool[] IsActiveWhenInputIs = new bool[16];

        public static void Xor(BitLine b1, BitLine b2, BitLine outputBitLine)
        {
            for (var i = 0; i < 16; i++)
            {
                outputBitLine.IsActiveWhenInputIs[i] = b1.IsActiveWhenInputIs[i] != b2.IsActiveWhenInputIs[i];
            }
        }

        public static void Nand(BitLine b1, BitLine b2, BitLine outputBitLine)
        {
            for (var i = 0; i < 16; i++)
            {
                outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] && b2.IsActiveWhenInputIs[i]);
            }
        }

        public static void Nor(BitLine b1, BitLine b2, BitLine b3, BitLine outputBitLine)
        {
            for (var i = 0; i < 16; i++)
            {
                outputBitLine.IsActiveWhenInputIs[i] = !(b1.IsActiveWhenInputIs[i] || b2.IsActiveWhenInputIs[i] || b3.IsActiveWhenInputIs[i]);
            }
        }

        public static void Decoder(BitLine b1, BitLine b2, BitLine b3, List<BitLine> lines, int listOriginalLength)
        {
            for (int optionNumber = 0; optionNumber < 8; optionNumber++)
            {
                for (var i = 0; i < 16; i++)
                {
                    int sum = 0;
                    if (b1.IsActiveWhenInputIs[i]) sum += 4;
                    if (b2.IsActiveWhenInputIs[i]) sum += 2;
                    if (b3.IsActiveWhenInputIs[i]) sum += 1;

                    lines[listOriginalLength + optionNumber].IsActiveWhenInputIs[i] = (sum == optionNumber);
                }
            }
        }

        public bool CheckEquals(BitLine other)
        {
            for (var i = 0; i < 16; i++)
            {
                if (this.IsActiveWhenInputIs[i] != other.IsActiveWhenInputIs[i])
                {
                    return false;
                }
            }
            return true;
        }

    }

    public class Solver
    {
        bool CheckIfSolutionExist(List<BitLine> lines, int linesLength, BitLine neededLine)
        {
            for (int i = 0; i < linesLength; i++)
            {
                if (lines[i].CheckEquals(neededLine))
                {
                    return true;
                }

            }
            return false;
        }

        bool HandleNand(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
        {
            if (nand)
            {
                for (int i = 0; i < listLength; i++)
                {
                    for (int j = i; j < listLength; j++)
                    {
                        BitLine.Nand(lines[i], lines[j], lines[listLength]);
                        if (Solve(lines, listLength + 1, false, nor, xor, decoder, neededLine))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        bool HandleXor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
        {
            if (xor)
            {
                for (int i = 0; i < listLength; i++)
                {
                    for (int j = i; j < listLength; j++)
                    {
                        BitLine.Xor(lines[i], lines[j], lines[listLength]);
                        if (Solve(lines, listLength + 1, nand, nor, false, decoder, neededLine))
                        {
                            return true;
                        }

                    }
                }
            }
            return false;
        }

        bool HandleNor(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
        {
            if (nor)
            {
                for (int i = 0; i < listLength; i++)
                {
                    for (int j = i; j < listLength; j++)
                    {
                        for (int k = j; k < listLength; k++)
                        {
                            BitLine.Nor(lines[i], lines[j], lines[k], lines[listLength]);
                            if (Solve(lines, listLength + 1, nand, false, xor, decoder, neededLine))
                            {
                                return true;
                            }

                        }
                    }
                }
            }
            return false;
        }

        bool HandleDecoder(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
        {
            if (decoder)
            {
                for (int i = 0; i < listLength; i++)
                {
                    for (int j = i; j < listLength; j++)
                    {
                        for (int k = j; k < listLength; k++)
                        {
                            BitLine.Decoder(lines[i], lines[j], lines[k], lines, listLength);
                            if (Solve(lines, listLength + 8, nand, nor, xor, false, neededLine))
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        public bool Solve(List<BitLine> lines, int listLength, bool nand, bool nor, bool xor, bool decoder, BitLine neededLine)
        {
            if ((!nand) && (!nor) && (!xor) && (!decoder))
            {
                return CheckIfSolutionExist(lines, listLength, neededLine);
            }
            else
            {
                if (HandleNand(lines, listLength, nand, nor, xor, decoder, neededLine))
                {
                    return true;
                }
                if (HandleNor(lines, listLength, nand, nor, xor, decoder, neededLine))
                {
                    return true;
                }
                if (HandleXor(lines, listLength, nand, nor, xor, decoder, neededLine))
                {
                    return true;
                }
                if (HandleDecoder(lines, listLength, nand, nor, xor, decoder, neededLine))
                {
                    return true;
                }
                return false;
            }
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            List<BitLine> list = new List<BitLine>();
            var bitLineList = new BitLine[200];
            for (int i = 0; i < 200; i++) bitLineList[i] = new BitLine();

            // set input bit:
            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    int checker = 1 << j;
                    bitLineList[j].IsActiveWhenInputIs[i] = ((checker & i) != 0);
                }
            }

            // set zero and one constant bits:
            for (int i = 0; i < 16; i++)
            {
                bitLineList[4].IsActiveWhenInputIs[i] = false;
                bitLineList[5].IsActiveWhenInputIs[i] = true;
            }

            list.AddRange(bitLineList);

            var neededBitLine = new BitLine();
            for (int i = 0; i < 16; i++)
            {
                neededBitLine.IsActiveWhenInputIs[i] = (i%7==0); // be true for any number that is devideble by 7 (0,7,14)
            }

            var solver = new Solver();
            Console.WriteLine(solver.Solve(list, 6, true, true, true, true, neededBitLine));
            Console.ReadKey();
        }
    }
}

Espero que esta vez sea una explicación válida: P

Ido Kessler
fuente
66
Es posible que desee incluir una descripción de alto nivel de cómo funciona este tipo de solucionador. No es inmediatamente obvio al leer este volcado de código completamente sin comentar.
Dave Tweed
2
Esta es una solución intrigante y espero que pueda proporcionar una descripción del algoritmo. ¿Has hecho algún caso de prueba similar para probar el método? (Por cierto, me gusta la sutil referencia de Douglas Adams)
Tut
2
Agregaré que probé este algoritmo con algún caso de prueba que podría verificar: x == 2, x == 3, x == 4, ..., x == 11. Como tarda mucho tiempo en ejecutarse, noto que x% 3 == 0 yx% 5 == 0 también podrían ser imposibles, y no pude encontrar una respuesta para ambos. Pero el algoritmo volvió verdadero para todos los casos anteriores para los cuales encontré una solución a mano.
Ido Kessler
3
+1! @IdoKessler, ¿puede intentar cambiar la entrada NAND de 2 bits con una entrada NOR de 2 bits y verificar si su software ofrece una solución? De hecho, con esa puerta, en lugar de una NAND, hay una solución.
Next-hack
3
@ next-hack devolvió True cuando lo cambié para usar un NOR de 2 bits
Ido Kessler
8

Esto no responde, para descartar la solución más obvia.

si1si2si4 4si8 .

si2si4 4 son iguales en todos los números válidos, podríamos pensar en implementar la expresión lógica:

(ni {X=0 0,X=3,X=6 6}) nand (si2 xor si4 4)

si1si4 4si8

Sin embargo, la simplificación de la expresión anterior es:

(X=0 0 o X=3 o X=6 6) o (si2=si4 4)

eso no es lo esperado:

(X=0 0 o X=3 o X=6 6) y (si2=si4 4)

Por esta razón, creo que es probable un error en la pregunta, siendo "nand" gate "ni"

pasaba por aqui
fuente
2
Tal vez sea cierto, tampoco encontré respuesta.
nrofis
2
+1. Creo que tienes razón, y la NAND debería ser una NOR.
Brian Drummond
2

Una respuesta válida a su pregunta sería cualquier circuito que devuelva siempre verdadero. Porque devolverá verdadero también si los números de entrada son 0,7 o 14.

Creo que la pregunta debería pedir explícitamente un circuito que resulte verdadero si los números de entrada son 0,7, o 14. Y de lo contrario, las salidas son falsas.

Agustin Tena
fuente
2
Wow, no esperaba tal respuesta. El circuito debería volver verdadero si y solo si la entrada es 0, 7 o 14 ...
nrofis
1
exactamente así.
Agustin Tena
2
+1 para mirar las especificaciones con cuidado. Esta es una mala ingeniería cuando se obtiene tal especificación de un cliente. En ese caso, la respuesta correcta es señalar el problema con la especificación al cliente y verificar lo que realmente quiere. Pero, para una pregunta de examen, muestra un pensamiento innovador y proporciona correctamente una respuesta muy simple.
Olin Lathrop
-3

Es factible. Como sugerencia, los dos bits intermedios son iguales para todos estos patrones de bits, por lo que su fijación producirá 0 que luego puede ser una entrada al decodificador con los otros dos bits. Las puertas restantes se aplican a las tres salidas del decodificador para proporcionar la salida correcta de un solo bit.

John
fuente
Ya hecho eso. No he encontrado ninguna combinación que resolver la cuestión ...
nrofis
Use el xor para reducir los cuatro bits a tres bits para el decodificador. El decodificador tendrá tres salidas que son 1 para los tres patrones coincidentes. Tampoco se unen y usan la puerta nand como inversor.
John
44
@ John ... Su solución produce 6 términos de producto (sin simplificar), 3 de los cuales no son válidos. En otras palabras, aunque su solución devuelve verdadero para 0, 7 o 14; también devuelve verdadero para 1, 6 u 8.
Tut