Funktory

  • W ogólności uznaje się, że bramki (poza NOT) mogą mieć dowolną liczbę wejść i ich słowny opis działania jest następujący:
    • AND - 1 jeśli wszystkie wejścia były równe 1
    • OR - 1 jeśli co najmniej jedno wejście było równe 1
    • XOR - 1 jeśli nieparzysta liczba wejść była równa 1
    • NAND, NOR, NXOR - tak jak AND, OR i XOR odpowiednio, ale negując wynik
  • Bramki NOT nie trzeba stosować bezpośrednio. Dozwolone jest umieszczenie "kółeczka" przy wejściu, które ma zostać zanegowane

Tablice Karnaugh

  • Aby znaleźć minimalną funkcję w algebrze Boole'a, która odpowiada zadanej tabelce prawdy, należy skonstruować tabelkę Karnaugh.
  • Wiersze i kolumny mają etykiety odpowiadające zmiennym logicznym:
    • dla dwóch zmiennych:
A\B01
0......
1......
  • dla trzech zmiennych:
AB\C01
00......
01......
11......
10......
  • dla czterech zmiennych:
AB\CD00011110
00............
01............
11............
10............
  • Tabelkę Karnaugh wypełnia się wg tabelki prawdy, ale uwaga na zastosowany kod Graya (w tabelce Karnaugh jest kolejność 00, 01, 11, 10)
  • Rozwiązanie "dla jedynek". Szukamy w tabelce skupisk jedynek, które spełniają pewne wymagania:
    • w skupisku musi być liczba jedynek równa 1, 2, 4, 8 lub 16 (potęga dwójki),
    • muszą one ze sobą sąsiadować tzn. tworzyć linię lub prostokąt,
    • sąsiedztwo to określone jest także dla brzegowych miejsc tzn. przykładowo jedynki z pierwszej kolumny mogą tworzyć skupisko z jedynkami z ostatniej kolumny.
  • Należy określić takie skupiska, żeby były jak największe i żeby ostatecznie każda jedynka do któregoś należała. Aby zapewnić pierwszą cechę, dopuszczalne jest by pewne jedynki należały do kilku skupisk.
  • Przykładowa tabelka:
AB\C01
0001
0111
1110
1001
  • Znalezione skupiska: (nie ma żadnych 8- ani 4-elementowych - od nich należało rozpocząć szukanie)
AB\C01
000 1
011 1
1110
1001
AB\C01
0001
01 11
11 10
1001
AB\C01
000 1
0111
1110
100 1

(tutaj właśnie sąsiedztwo jest oparte na brzegowych wartościach)

  • Dla każdego skupiska szukamy teraz funkcji, która je opisuje. Patrząc na wiersze i kolumny, szukamy które wejściowe zmienne logiczne mają dla danego skupiska stałą wartość. Spójrzmy na pierwsze skupisko - widać, że A jest dla niego zawsze równe 0, B zmienia się między 0 i 1, C jest zawsze równe 1. Pomijamy zatem B i dla tego skupiska zapisujemy funkcję: ~A*C
  • Analogicznie dla kolejnych skupisk otrzymujemy: B*~C oraz ~B*C
  • Poszukiwana funkcja dla pierwotnych danych to dysjunkcja znalezionych funkcji dla skupisk:
    f(A, B, C) = (~A*C) + (B*~C) + (~B*C)
  • Rozwiązanie "dla zer" jest analogiczne. Różnica polega na tym, że szukamy skupisk zer i po połączeniu znakami dysjunkcji wszystkich funkcji cząstkowych, otrzymujemy zanegowaną postać funkcji pierwotnej. Zobaczmy to na przykładzie dla tych samych danych:
AB\C01
00 01
0111
1110
10 01
AB\C01
0001
0111
111 0
1001
  • Tym razem są dwa skupiska. Jedno z nich jest tylko 1-elementowe, ale musimy je wziąć pod uwagę, bo nie może zostać pominięty żaden element.
  • Nasza funkcja wynikowa to:
    ~f(A, B, C) = (~B*~C) + A*B*C
  • Z praw de Morgana można otrzymać oczywiście postać niezanegowaną postać funkcji:
    ~[~f(A, B, C)] = f(A, B, C)
    = ~[(~B*~C) + A*B*C]
    = ~(~B*~C) * ~(A*B*C)
    = (B + C) * (~A + ~B + ~C)
  • Rozwiązania "dla jedynek" i "dla zer" są sobie równoważne. Jak widać z powyższego przykładu, wybór metody czasem prowadzi do różnej liczby kroków do wykonania.

Operacje bitowe w języku C

  • Operator AND: &
    int x = 7, y = 10;
    printf("%d\n", x & y); // 2
    /*  
     *   0111b = 7
     *   1010b = 10
     * -------
     * & 0010b = 2
     */
  • Operator OR: |
    int x = 7, y = 10;
    printf("%d\n", x | y); // 15
    /*
     *   0111b = 7
     *   1010b = 10
     * -------
     * | 1111b = 15
     */
  • Operator XOR: ^
    int x = 7, y = 10;
    printf("%d\n", x ^ y); // 2
    /*
     *   0111b = 7
     *   1010b = 10
     * -------
     * ^ 1101b = 13
     */
  • Operator NOT: ~
    int x = 0;
    printf("%d\n", ~x); // -1
    /*
     *   0000b = 0
     * -------
     * ~ 1111b = -1
     */
  • Operator przesunięcia bitowego w lewo: <<
    int x = 7, y = 1;
    printf("%d\n", x << y); // 28
    /*
     *       0111b = 7
     * -----------
     * << 1  1110b = 14
     */
  • Operator przesunięcia bitowego w prawo: >>
    int x = 7, y = 1;
    printf("%d\n", x >> y); // 3
    /*
     *       0111b = 7
     * -----------
     * >> 1  0011b = 3
     */

Uwaga, zwróć uwagę na różnicę pomiędzy & i &&

int a = 1, b = 2;
if (a && b) {
    printf("TO SIE POJAWI\n");
}
if (a & b) {
    printf("TO SIE NIE POJAWI\n");
}