Circuito logico digitale - domanda d'esame


14

Ho una domanda da un esame che non sono riuscito a risolvere:

Devo costruire un circuito logico digitale che sta ricevendo un numero di 4 bit e restituire truese il numero è 0, 7o 14. Ne ho solo unoXOR gate (2 ingressi), uno NOR(3 ingressi), uno NAND(2 ingressi) e un decodificatore da 3 a 8.

Penso che quella domanda sia irrisolvibile, non ho trovato alcuna combinazione in grado di farlo. Qualche idea su come risolverlo?


1
Come suggerimento: dati 4 bit e un decodificatore 3-8, devi trattare uno dei bit in modo diverso.
Brian Drummond,

2
@BrianDrummond, ma lo so già e non sono ancora riuscito a risolverlo. Ogni soluzione che ho provato sembra che manchi un gate OR. Non riesco a trovare una tale combinazione con le porte date che può risolvere il problema ... Nota che ho solo UN cancello per tipo ...
nrofis,

3
@BrianDrummond: se pubblichi una descrizione della soluzione che ritieni esista, potremmo verificarla. È difficile dire che non esiste una soluzione, ma è facile verificare se una soluzione è valida.
pasaba por aqui,

2
@Ido Kessler ... Sono stato incuriosito dalla tua soluzione e se la tua prova è corretta, mi dispiace che tu l'abbia eliminata. Nessuno finora sembra avere una soluzione. Forse se includessi una descrizione del tuo algoritmo, migliorerebbe la risposta. Quanto sei sicuro che sia corretto e privo di bug?
Tut

3
@jalalipop, l'ho fatto ieri. Ido Kessler e pasaba por aqui avevano ragione, il mio professore disse che la domanda era sbagliata e che la NAND avrebbe dovuto essere NOR ....
Nrofis,

Risposte:


24

Ho scritto un algoritmo in C # che prova ogni possibile combinazione di quelli Nor 3->1 Xor 2->1 Nand 2->1eDecoder 3->8 .

Dopo averlo eseguito per 7½ milioni di anni 2 ore, ha restituito 42 false. Credo che ciò provi che la domanda non ha risposta poiché questo algoritmo controlla ogni possibile combinazione. :)

Mi è stato chiesto di descriverlo, quindi la parte successiva è una spiegazione delle parti del codice, parte per parte. TL; DR : puoi semplicemente saltare al codice alla fine :)


Parliamo delle linee di input, hanno 0 o 1 stati e per ciascuno dei possibili input (da 0 a 15) hanno valori diversi:

per la prima riga sembra che: 0 1 0 1 0 1 ... Il secondo è: 0 0 1 1 0 0 1 1 ... il terzo: 0 0 0 0 1 1 1 1 .... come binario contando ... hai avuto l'idea: P

Quindi ho creato un oggetto che rappresenta ogni linea in ciascuno dei suoi stati:

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

Come si dice bitLine.IsActiveWhenInputIs [5] restituisce se la linea era attiva quando l'input era 5.

Questo è un codice che crea del tutto le linee di input:

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

Creeremo anche linee di bit "sempre vero" e "sempre falso" per fornire un input "0" costante o un input "1".

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

Ora, se noti, quello che stiamo cercando è in realtà un bitLine specifico, vero quando l'input è 0, 7, 14. Rappresentiamolo nella nostra classe:

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

Ciò ha reso le cose davvero semplici: quello che stiamo effettivamente cercando è un modo per "forgiare" questo necessario BitLine dalla linea di bit di input (ecco come rappresento al mio programma quello che voglio che sia il mio output).

Ora, questo è il modo di andare avanti: ogni volta che usiamo qualche elemento logico sulle nostre linee di bit come Xor, Nor, Nando anche ilDecoder , in realtà stiamo creando una nuova linea di bit \ S. Conosciamo il valore di ciascuna delle linee in ogni possibile input da 0 a 15, quindi possiamo calcolare il nuovo valore bitLine in ogni possibile input!

Nand Nor e Xor sono tutti semplici:

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]);
    }
}

Per ogni possibile input, rappresenta come agirà il nuovo BitLine.

Gestire il decodificatore è un po 'complicato, ma l'idea è "se i bit in ingresso rappresentano il numero x in binario, allora la x-esima riga di bit sarà vera, mentre tutti gli altri saranno falsi. A differenza dell'altro funzione, questo ottiene un array di bitline e aggiunge 8 nuovi bitline all'array.

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);
        }
    }
}

Ora abbiamo tutti i nostri elementi di base, quindi parliamo dell'algoritmo:

Faremo un algoritmo ricorsivo, ad ogni profondità proverà ad usare altri elementi (né \ ne \ xor \ decoder) sulle linee di bit attualmente disponibili, e quindi impostare l'elemento su inutilizzabile per la prossima profondità ricorsiva. Ogni volta che arriviamo in fondo e non abbiamo più elementi da usare, controlleremo se abbiamo una bitline che è quello che stavamo cercando.

Questo codice verifica in qualsiasi momento se l'attuale gruppo di linee contiene la linea che stiamo cercando:

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

Questa è la funzione che utilizza per verificare se due linee sono uguali:

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

Ok, quindi ora per la parte principale, questo è l'algoritmo principale:

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

Questa funzione riceve un elenco delle bitLine disponibili, la lunghezza dell'elenco, un valore booleano che indica se ogni elemento è attualmente disponibile (xor / nor / nand / decoder) e un bitLine che rappresenta il bitLine che stiamo cercando.

In ogni fase, controlla se abbiamo altri elementi da usare, in caso contrario - controlla se archiviamo la nostra bitline necessaria.

Se abbiamo ancora più elementi, quindi per ogni elemento chiama una funzione che dovrebbe gestire la creazione di nuove bitLine usando quegli elementi e chiamando successivamente la profondità recessiva successiva.

Le funzioni del gestore successivo sono tutte piuttosto semplici, possono essere tradotte in "scegli 2 \ 3 tra le bitline disponibili e combinale usando l'elemento pertinente. Quindi chiama la profondità successiva della ricorsione, solo che questa volta non conterrà questo elemento! ".

quelle sono le funzioni:

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

E questo è tutto, chiamiamo semplicemente questa funzione con la linea necessaria che stiamo cercando, e controlla ogni possibile combinazione delle parti elettriche per verificare se è possibile combinarle in modo tale che alla fine sarà una singola linea prodotto con i valori necessari.

* nota che uso sempre lo stesso elenco, quindi non dovrò creare sempre nuove istanze di bitline. Gli do un buffer di 200 per questo motivo.


Questo è il programma 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();
        }
    }
}

Spero che questa volta sia una spiegazione valida: P


6
Potresti voler includere una descrizione di alto livello di come funziona questo tipo di solutore. Non è immediatamente ovvio leggere questo dump del codice completamente non commentato.
Dave Tweed

2
Questa è una soluzione intrigante e spero che tu possa fornire una descrizione dell'algoritmo. Hai fatto casi di test simili per dimostrare il metodo? (A proposito, mi piace il sottile riferimento di Douglas Adams)
Tut

2
Aggiungerò che ho provato questo algoritmo con alcuni casi di test che ho potuto verificare: x == 2, x == 3, x == 4, ..., x == 11. Dato che ci vuole molto tempo per correre, noto che x% 3 == 0 e x% 5 == 0 potrebbero anche essere impossibili, e non sono riuscito a trovare una risposta per entrambi. Ma l'algoritmo è tornato vero per tutti i casi precedenti per i quali ho trovato una soluzione a mano.
Ido Kessler,

3
+1! @IdoKessler puoi provare a cambiare la NAND di input a 2 bit con un NOR di input a 2 bit e verificare se il tuo software offre una soluzione? In effetti, con quel cancello, invece di una NAND, c'è una soluzione.
prossimo hack del

3
@ next-hack ha restituito True quando l'ho modificato per utilizzare un NOR a 2 bit
Ido Kessler

8

Questa è una non risposta, per scartare la soluzione più ovvia.

B1B2B4B8 .

B2B4

( {X=0,X=3,X=6}) nand (B2 xor B4)

B1B4B8

Tuttavia, la semplificazione dell'espressione precedente è:

(X=0 o X=3 o X=6) o (B2=B4)

non è quello previsto:

(X=0 o X=3 o X=6) e (B2=B4)

Per questo motivo, ritengo probabile un errore nella domanda, essendo "nand" gate un "né" uno.


2
Forse è vero, non ho nemmeno trovato risposta.
nrofis,

2
+1. Credo che tu abbia ragione, e la NAND dovrebbe essere una NOR.
Brian Drummond,

2

Una risposta valida alla tua domanda sarebbe qualsiasi circuito che ritorni sempre vero. Perché restituirà vero anche se i numeri di input sono 0,7 o 14.

Penso che la domanda dovrebbe esplicitamente chiedere un circuito che sia vero se i numeri di ingresso sono 0,7, o 14. E che altrimenti produce falso.


2
Wow, non mi aspettavo una simile risposta. Il circuito dovrebbe tornare vero se e solo se l'ingresso è 0, 7 o 14 ...
nrofis,

1
esattamente come quello.
Agustin Tena,

2
+1 per esaminare attentamente le specifiche. Questa è una cattiva ingegneria quando si ottengono tali specifiche da un cliente. In tal caso, la risposta giusta è segnalare il problema con le specifiche al cliente e verificare ciò che vogliono veramente. Ma, per una domanda d'esame, mostra come pensare fuori dagli schemi e fornisce correttamente una risposta molto semplice.
Olin Lathrop,

-3

È fattibile. Come suggerimento, i due bit centrali sono uguali per tutti questi pattern di bit, quindi il loro xoring produrrà 0 che può quindi essere un input per il decoder con gli altri due bit. Le porte rimanenti vengono applicate alle tre uscite del decodificatore per fornire l'uscita a bit singolo corretta.


Già fatto. Non ho trovato alcuna combinazione che risolva la domanda ...
Nrofis,

Utilizzare xor per ridurre i quattro bit a tre bit per il decodificatore. Il decodificatore avrà tre uscite che sono 1 per i tre modelli corrispondenti. Né insieme e usano il nand gate come un inverter.
John,

4
@John ... La tua soluzione genera 6 termini di prodotto (non semplificati), 3 dei quali non sono validi. In altre parole, sebbene la tua soluzione ritorni vera per 0, 7 o 14; restituisce anche true per 1, 6 o 8.
Tut
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.