Позначається оборотом промови «чи…, чи…» Складове твердження «чи A, чи B» вважається істинним, коли істинно чи A, чи B, але з обидва одночасно; в іншому випадку складне твердження хибне.

Тобто. результат дійсний (рівний 1), якщо A не дорівнює B (A≠B).

Цю операцію нерідко порівнюють із диз'юнкцією тому, що вони дуже схожі за властивостями, і обидві мають схожість із союзом «або» у повсякденному мовленні. Порівняйте правила цих операцій:

1. істинно, якщо істинно або , абообидва одразу.

2. істинно, якщо істинно або, але необидва одразу.

Операція виключаєостанній варіант ("обидва відразу") і з цієї причини називається виключним "АБО". НеоднозначністьПриродною мовою є те, що союз «або» може застосовуватися в обох випадках.

5. Імплікація (логічне слідування)утворюється з'єднанням двох висловлювань за допомогою обороту мови «якщо …, то ….».

Запис: А®В

Складове висловлювання, утворене з допомогою операції імплікації, хибно тоді й лише тоді, коли з істинної передумови (першого висловлювання) випливає хибний висновок (друге висловлювання).

Тобто. якщо з 1 слідує 0, то результат – 0, в інших випадках – 1.

Наприклад, висловлювання «Якщо число ділиться на 10, воно ділиться на 5» істинно, т.к. істинні і перший і другий вислів.

Висловлювання «Якщо число ділиться на 10, воно ділиться на 3» хибно, т.к. з істинної причини робиться хибний висновок.

"Цей чотирикутник - квадрат" (А) та "Біля цього чотирикутника можна описати коло" (У). Тоді складне висловлювання, читається як "Якщо цей чотирикутник квадрат, то біля нього можна описати коло".

У звичайній мові зв'язка "якщо то"описує причинно-наслідковий зв'язок між висловлюваннями. Але в логічних операціях сенс висловлювань не враховується. Розглядається лише їхня істинність чи хибність. Тому не треба бентежитися "безглуздістю" імплікацій, освічених висловлюваннями, зовсім не пов'язаними за змістом. Наприклад, такими: "якщо президент США - демократ, то в Африці водяться жирафи", "якщо кавун - ягода, то в бензоколонці є бензин".

6. Еквівалентність (логічна рівність, ~ º ¢) утворюється з'єднанням двох висловлювань в одне за допомогою мовного звороту «…тоді і тільки тоді, коли...»

Складове висловлювання, утворене операцією еквівалентності, істинно тоді й лише тоді, коли обидва висловлювання одночасно або хибні, або щирі.

Наприклад, вислів «Комп'ютер може проводити обчислення тоді й тільки тоді, коли він включений» і «Комп'ютер не може робити обчислення тоді і тільки тоді, коли він не включений» - істинні, оскільки обидва прості висловлювання одночасно є істинними.


Таблиці істинності

Для кожного складового висловлювання (логічної функції) можна побудувати таблицю істинності, яка визначає його істинність чи хибність за всіх можливих комбінаціях вихідних значень простих висловлювань.

Таблиця істинностіце табличне подання логічної схеми (операції), в якому перераховані всі можливі поєднання значень істинності вхідних сигналів (операндів) разом зі значенням істинності вихідного сигналу (результату операції) для кожного з цих поєднань.

Відобразимо вище розглянуті логічні операціїу таблиці істинності:

В алгебрі висловлювань всі логічні функції шляхом логічних перетворень можуть бути зведені до трьох базових: логічного додавання, логічного множення та логічного заперечення.

Доведемо, що операція імплікація А®В є рівносильною логічному виразу:

Теги: Сі бітові операції, побітові операції, побітове додавання, побітове множення, бітовий зсув вліво, бітовий зсув вправо

Вступ

Я си Сі іноді називають макроассемблером за його потяг до заліза. Якщо не використовувати оптимізацію, можна навіть приблизно оцінити, які конструкції на асемблері перетворюється код програми. Простота і мінімалізм мови (простоту мови не плутати з простотою програмування мовою) призвели до того, що на багатьох платформах залишається єдиною високорівневою мовою програмування. Без огляду на побітові операції, звичайно, вивчення мови було б неповним.

Побітові операції, як відомо з назви, дозволяють оперувати безпосередньо з бітами. Багато прикладів використання побітових операцій можна знайти, наприклад, у книзі Генрі Уоррена «Алгоритмічні трюки для програмістів». Тут ми розглянемо лише самі операції та примітивні алгоритми.

Побітові І, АБО, НЕ, що виключає АБО

Нагадаю для початку, що логічні операції І, АБО, що виключає АБО і НЕ можуть бути описані за допомогою таблиць істинності

Логічний оператор НЕ
X NOT X
0 1
1 0

У побітових (bit-wise) операціях значення біта, що дорівнює 1, розглядається як логічна істина, а 0 як брехня. Побітове І (оператор &) бере два числа і логічно множить відповідні біти. Наприклад, якщо логічно помножити 3 на 8, то отримаємо 0

Char a = 3; char b = 8; char c = a & b; printf("%d", c);

Так як у двійковому вигляді 3 у вигляді однобайтного цілого є

Перший біт змінної c дорівнює логічному добутку першого біта числа a першого біта числа b. І так для кожного біта.

00000011
00001000
↓↓↓↓↓↓↓↓
00000000

Відповідно, побітовий добуток чисел 31 і 17 дасть 17, так як 31 це 00011111 , а 17 це 00010001

00011111
00010001
↓↓↓↓↓↓↓↓
00010001

Побітовий добуток чисел 35 і 15 дорівнює 3.

00100011
00001111
↓↓↓↓↓↓↓↓
00000011

Аналогічно працює операція побітового АБО (оператор |), крім того, що вона логічно підсумовує відповідні біти чисел без перенесення.

Наприклад,

Char a = 15; char b = 11; char c = a | b; printf("%d", c);

виведе 15, тому що 15 це 00001111, а 11 це 00001011

00001111
00001011
↓↓↓↓↓↓↓↓
00001111

Побітове АБО для чисел 33 і 11 поверне 43, тому що 33 це 00100001, а 11 це 00001011

00100001
00001011
↓↓↓↓↓↓↓↓
00101011

Побитовое заперечення (оператор ~) працює задля окремого біта, а всього числа цілком. Оператор інверсії змінює брехню на істину, а істину на брехню, кожного бита. Наприклад,

Char a = 65; char b = ~a; printf("%d", b);

Виведе -66, тому що 65 це 01000001, а інверсія дасть 10111110

що дорівнює -66. До речі, ось алгоритм для того, щоб зробити число негативним: для знаходження додаткового коду числа його треба інвертувати та додати до нього одиницю.

Char a = 107; char b = ~a + 1; printf("a = %d, -a = %d", a, b);

Виключає АБО (оператор ^) застосовує побітову операцію XOR. Наприклад, для чисел

Char a = 12; char b = 85; char c = a^b; printf("%d", c);

буде виведено 89, так як a дорівнює 00001100 а b дорівнює 01010101 . У результаті отримаємо 01011001

Іноді логічні оператори && та || плутають з операторами & та |. Такі помилки можуть існувати в коді досить довго, тому що такий код у ряді випадків працюватиме. Наприклад, для чисел 1 і 0. Але оскільки у си істиною є будь-яке ненульове значення, то побітове множення чисел 3 і 4 поверне 0, хоча логічне множення має повернути істину.

Inta = 3; int b = 4; printf("a&b = %d\n", a&b); //виведе 0 printf("a && b = %d\n", a && b);//виведе не 0 (конкретніше, 1)

Операції побитового зсуву

Операцій зсуву дві - бітовий зсув вліво (оператор<<) и битовый сдвиг вправо (оператор >>). Бітовий зсув праворуч зсуває біти числа праворуч, дописуючи зліва нулі. Бітове зрушення вліво робить протилежне: зрушує біти вліво, дописуючи праворуч нулі. Вийшли межі числа біти відкидаються.

Наприклад, зсув числа 5 вліво на 2 позиції

00000101 << 2 == 00010100

Зсув числа 19 праворуч на 3 позиції

00010011 >> 3 == 00000010

Незалежно від архітектури (big-endian, або little-endian, або middle-endian) числа в двійковому вигляді представляються зліва направо, від значущого біта до менш значущого. Побітовий зсув приймає два операнда - число, над яким необхідно зробити зсув, і число біт, на яке необхідно зробити зсув.

Inta = 12; printf("%d<< 1 == %d\n", a, a << 1); printf("%d << 2 == %d\n", a, a << 2); printf("%d >> 1 == %d\n", a, a >> 1); printf("%d >> 2 == %d\n", a, a >> 2);

Так як зсув вправо (>>) дописує зліва нулі, то для цілих чисел операція рівнозначна цілісному поділу навпіл, а зрушення вліво множенню на 2. Зробити бітовий зсув для числа з плаваючою точкою без явного приведення типу не можна. Це викликано тим, що для сі не визначено уявлення числа з плаваючою точкою. Однак, можна перемістити число типу float в int, потім зрушити і повернути назад

Float b = 10.0f; float c = (float) (*((unsigned int*)&b) >> 2); printf("%.3f >> 2 = %.3f", b, c);

Але ми, звичайно, отримаємо не 5.0f, а зовсім інше число.

Особливістю операторів зсуву і те, що можуть по-різному поводитися з числами зі знаком і знака, залежно від компілятора. Справді, від'ємне число зазвичай містить один біт символу. Коли ми будемо зрушувати вліво, він може зникнути, число стане позитивним. Однак компілятор може зробити так, що зсув залишиться знакопостійним і проходитиме за іншими правилами. Те саме і для зсуву вправо.

Unsigned int ua = 12; signed int sa = -11; printf("ua = %d, ua >> 2 = %d\n", ua, ua >> 2); printf("sa = %d, sa >> 2 = %d\n", sa, sa >> 2); printf("(unsigned) sa = %u, sa >> 2 = %u\n", sa, sa >> 2); printf("sa = %d, ((unsigned) sa) >> 2 = %d", sa, ((unsigned) sa) >> 2);

У разі при першому зрушенні все працює, як і задумано, оскільки число без знака. У другому випадку компілятор VSE2013 залишає знак. Однак якщо подивитися на подання цього числа, як беззнакового, зсув відбувається за іншими правилами, зі збереженням лівого біта. В останньому рядку, якщо привести число зі знаком до числа без знака, то відбудеться звичайний зсув, і ми отримаємо в результаті позитивне число.

Побітові оператори та оператори зсуву не змінюють значення числа, повертаючи нове. Вони також як і арифметичні оператори можуть входити до складу складного привласнення

Inta = 10; int b = 1; a >>= 3; a ^= (b<< 3); и т.д.

Приклади

1. Напишемо функції, які дозволяють визначати та змінювати певний біт числа

Щоб дізнатися, який біт (1 чи 0) стоїть позиції n, скористаємося логічним множенням.

Нехай є число 9

00001001

Потрібно з'ясувати, чи виставлений біт на позиції 3 (починаючи з нуля). Для цього помножимо його на число, у якого всі біти дорівнюють нулю, крім третього:

00001001 & 00001000 = 00001000

Тепер дізнаємося значення біта у позиції 6

00001001 & 01000000 = 00000000

Таким чином, якщо ми отримуємо відповідь, що дорівнює нулю, то на потрібній позиції знаходиться нуль, інакше одиниця. Щоб отримати число, що складається з нулів з одним бітом на потрібній позиції, посунемо 1 на потрібне число біт вліво.

#include #include #include int checkbit(const int value, const int position) ( int result; if ((value & (1<< position)) == 0) { result = 0; } else { result = 1; } return result; } void main() { int a = 3; size_t len = sizeof(int) * CHAR_BIT; size_t i; for (i = 0; i < len; i++) { printf("%d", checkbit(a, i)); } _getch(); }

Зауважте, що у функції умова записана так

(value & (1<< position)) == 0

Тому що без дужок спочатку буде обчислено рівність нулю і лише потім виконано множення.

Value & (1<< position) == 0

Функцію можна спростити

Int checkbit(const int value, const int position) ( return ((value & (1<< position)) != 0); }

Функція, яка виставляє біт на n-й позиції за одиницю.

Відомо, що логічне додавання будь-якого біта з 1 дорівнюватиме 1. Так що для установки n-го біта потрібно логічно скласти число з таким, у якого всі біти, крім потрібного, дорівнюють нулю. Як отримати таку кількість, вже розглянуто.

Int setbit(const int value, const int position) ( return (value | (1<< position)); }

Функція, яка встановлює біт на n позиції в нуль.

Для цього потрібно, щоб усі біти числа, крім n-го, не змінилися. Помножимо число на таке, у якого всі біти дорівнюють одиниці, крім біта під номером n. Наприклад

0001011 & 1110111 = 0000011

Щоб отримати таку маску, спочатку створимо число з нулями та однією одиницею, а потім інвертуємо його.

Int unsetbit(const int value, const int position) ( return (value & ~(1)<< position)); }

Функція, що змінює значення n-го біта протилежне.

Для цього скористаємося функцією виключає або: застосуємо операцію XOR до числа, яке складається з одних нулів та однієї одиниці на місці потрібного біта.

Int switchbit(const int value, const int position) ( return (value ^ (1<< position)); }

Перевірка

#include #include #include int checkbit(const int value, const int position) ( return ((value & (1<< position)) != 0); } int setbit(const int value, const int position) { return (value | (1 << position)); } int unsetbit(const int value, const int position) { return (value & ~(1 << position)); } int switchbit(const int value, const int position) { return (value ^ (1 << position)); } void printbits(int n) { //CHAR_BIT опеределён в библиотеке limits.h //и хранит число бит в байте для данной платформы size_t len = sizeof(int)* CHAR_BIT; size_t i; for (i = 0; i < len; i++) { printf("%d", checkbit(n, i)); } printf("\n"); } void main() { int a = 3; size_t len = sizeof(int) * CHAR_BIT; size_t i; printbits(a); a = setbit(a, 5); printbits(a); a = unsetbit(a, 5); printbits(a); a = switchbit(a, 11); printbits(a); a = switchbit(a, 11); printbits(a); _getch(); }

Бітові прапори

Розглянемо синтетичний приклад. Нехай ми маємо три логічні змінні, і нам потрібно вивести певне значення залежно від усіх цих змінних відразу. Очевидно, що може бути 2-3 можливих варіантів. Запишемо цю умову у вигляді розгалуження:

#include int main() ( unsigned char a, b, c; a = 1; b = 0; c = 0; else ( printf("true true false"); ) ) else ( if (c) ( printf("true false true"); ) else ( printf("true false false"); ) ) ) else ( if (b) ( if (c) ( printf("false true true"); ) else ( printf("false true false"); ) ) else ( if (c) ( printf("false true true"); ) else ( printf( "false false false"); ) ) ) _getch(); return 0; )

Ми отримали 8 гілок. Нехай тепер нам довелося додати ще одну умову. Тоді кількість гілок подвоїться, і програма стане ще складнішою для розуміння та налагодження. Перепишемо приклад.

Якщо кожне з наших логічних значень зрушити на своє число біт ліворуч і логічно скласти, то ми отримаємо свою унікальну комбінацію біт залежно від значень a, b і c:

#include #include void printbits (int n) ( int i; for (i = CHAR_BIT - 1; i >= 0; i--) ( printf("%d", (n & (1)<< i)) != 0); } printf("\n"); } int main() { unsigned char a, b, c; unsigned char res; a = 1; b = 0; c = 0; res = c | b << 1 | a << 2; printbits(res); a = 0; b = 1; c = 1; res = c | b << 1 | a << 2; printbits(res); a = 1; b = 0; c = 1; res = c | b << 1 | a << 2; printbits(res); _getch(); return 0; }

Використовуємо цей підхід до нашого завдання та замінимо розгалуження на switch:

#include int main() ( unsigned char a, b, c; unsigned char res; a = 1; b = 0; c = 0; res = c | b<< 1 | a << 2; switch (res) { case 0b00000000: printf("false false false"); break; case 0b00000001: printf("false false true"); break; case 0b00000010: printf("false true false"); break; case 0b00000011: printf("false true true"); break; case 0b00000100: printf("true false false"); break; case 0b00000101: printf("true false true"); break; case 0b00000110: printf("true true false"); break; case 0b00000111: printf("true true true"); break; } _getch(); return 0; }

Цей метод часто використовується для призначення опцій функцій у різних мовах програмування. Кожен прапор приймає свою унікальну назву, а їхнє спільне значення як логічна сума всіх прапорів, що використовуються. Наприклад, бібліотека fcntl.

Поведінка

Елементи Виключає АБО, Виключає АБО-НЕ, Непарність та парність обчислюють відповідну функцію від значень на входах і видають результат на вихід.

За замовчуванням, непідключені входи ігноруються - тобто якщо входи дійсно не мають нічого підключеного до них - навіть дроти. Таким чином, ви можете додати 5-вхідний елемент, але підключити тільки два входи, і він буде працювати як 2-вхідний елемент; це позбавляє вас необхідності турбуватися про налаштування кількості входів щоразу при створенні елемента. (Якщо всі входи не підключені, то на виході значення помилки X.) Деякі користувачі, однак, воліють, щоб Logisim наполягав, щоб усі входи були підключені, оскільки це відповідає реальним елементам. Ви можете увімкнути цю поведінку, вибравши меню Проект > Параметри…, перейшовши на вкладку Моделювання, та вибравши варіант Помилка для невизначених входів для Вихід елемента при невизначеності.

Двохвхідна таблиця істинності для елементів наступна.

xyВиключне АБО Виключне АБО-НЕНепарністьпарність
0 0 0 1 0 1
0 1 1 0 1 0
1 0 1 0 1 0
1 1 0 1 0 1

Як ви можете бачити, елементи Непарність та Виключне АБО поводяться однаково у разі двох входів; аналогічно, елементи парність і виключає АБО-НЕ поводяться однаково. Але якщо входів з певним значенням більше двох, то елемент Виключне АБО буде давати на виході 1, коли одиниця суворо одному вході, тоді як елемент Непарність дасть на виході 1, коли одиниця на непарному кількості входів. Елемент Виключне АБО-НЕ даватиме на виході 1, коли входів з одиницею суворо неодин, тоді як елемент парність дасть 1, коли входів з одиницею парна кількість. Елементи Виключне АБО та Виключне АБО мають атрибут, названий Багатовхідна поведінка, який дозволяє налаштувати їх на використання поведінки елементів Непарність та парність.

Якщо на будь-яких входах значення помилки (наприклад, якщо суперечливі значення надходять на той самий провід) або плаваюче значення, то на виході буде значення помилки.

Багатобітні версії кожного елемента виконуватимуть свої однобітні перетворення над входами порозрядно.

Примітка:багато фахівців стверджують, що поведінка фігурного елемента виключає чи має відповідати поведінці елемента непарність, але з цього питання немає згоди. Поводження Logisim за замовчуванням для елемента Виключне АБО засноване на стандарті IEEE 91. Це також узгоджується з інтуїтивним розумінням терміну Виключне АБО: офіціант, що запитує, хочете ви гарнір з картопляного пюре, моркви, зеленого горошку, або шаткованої капусти, прийме тільки один вибір, а не три, незалежно від того, що вам можуть сказати деякі фахівці. (Повинен визнати, однак, що я не піддав цю заяву серйозним випробуванням.) Ви можете налаштувати елементи Виключне АБО та Виключне АБО-НЕ на використання одного з варіантів, змінюючи його атрибут Багатовхідна поведінка.

Контакти (передбачається, що компонент спрямований на схід)

Західний край (входи, розрядність відповідає атрибуту Біти даних)

Вхід компонента. Їх буде стільки, скільки зазначено в атрибуті Кількість входів.

Зауважте, що якщо ви використовуєте фігурні елементи, то західний край елементів виключає або виключає чи не буде викривлений. Проте вхідні контакти розташовані навряд. Logisim малює короткі відрізки щоб показати це; якщо ви перекриєте відрізок, програма без попереджень припускати, що ви не хотіли перекрити його. При використанні "Вигляду для друку", ці відрізки не будуть відображені, якщо не підключені до проводів.

Східний край (вихід, розрядність відповідає атрибуту Біти даних)

Вихід елемента, значення якому обчислюється виходячи з поточних значень на входах, як описано вище.

Атрибути

Коли компонент вибраний або вже доданий, клавіші від 0 до 9 змінюють його атрибут Кількість входів, комбінації від Alt-0 до Alt-9 змінюють його атрибут Біти даних, а клавіші зі стрілками змінюють його атрибут Напрямок.

Напрямок Напрямок компонента (його виходу щодо його входів). Біти даних Розрядність входів та виходів компонента. Розмір елемента Визначає, чи слід малювати широку або вузьку версію компонента. Це не впливає на кількість входів, що визначається атрибутом Кількість входів; правда, якщо кількість входів перевищує 3 (для вузького компонента) або 5 (для широкого), то елемент малюватиметься з "крилами", щоб вмістити запитану кількість входів. Кількість входів Визначає, скільки контактів на західному краї матиме компонент. Багатовхідна поведінка (тільки для Виключне АБО і Виключне АБО-НЕ) Коли входів три або більше, то значення на виході елементів Виключне АБО та Виключне АБО-НЕ буде засноване або на тому, що 1 строго на одному вході (за замовчуванням), або на непарній кількості входів.

Найпростіші логічні операції

Найпростіші логічні операції відносяться до двозначної логіки. Їх 4 штуки: "НІ", "І", "АБО", "XOR". Також для позначення цих операцій використовують різні значки (“~”, “&” тощо).

При записі логічних формул замість слів “істина” та “брехня” зазвичай використовують стандартні міжнародні позначення:
Замість "істина" пишуть: true, T, t, 1.
Замість "брехня" пишуть: false, F, f, 0.

"НІ"

Операція “НЕ” перетворює істину на брехню, а брехня на істину:

НЕ true = false
НЕ false = true

Ця операція має різні інші назви: “логічне НЕ”, “заперечення”, “логічне заперечення”, “інверсія”, “логічна інверсія”. Для міжнародних позначень замість НЕ пишуть NOT.

У природній мові цієї операції відповідає додавання слів “неправда, що...” на початку висловлювання. Наприклад:

Застосування операції “НЕ” до висловлювання (1):

"Неправда, що Сурков винен мені грошей". (2)

Якщо вислів (1) хибний, то вислів (2) істинний. Якщо вислів (2) хибний, то вислів (1) істинний.

Неважко зрозуміти, що подвійне застосування “НЕ” повертає нас до колишньої істинності.

"Неправда, що неправда, що Сурков винен мені грошей". (3)

Істинність висловлювання (3) завжди збігається з істинністю висловлювання (1).

"І"

Операція "І" застосовується до двох висловлювань. Її результат "істина", тільки якщо обидва висловлювання істинні (а інакше "брехня"):

false І false = false
false І true = false
true І false = false
true І true = true

Ця операція має різні інші назви: “логічне І”, “кон'юнкція”, “логічне множення”. Для міжнародних позначень замість “І” пишуть “AND”.

У природній мові цієї операції відповідає вставка спілки "і" між висловлюваннями. Наприклад:

“Сурков винен мені грошей”. (1)
"Петров винен мені грошей". (2)

Застосування операції “І” до висловів (1) та (2):

“Сурков винен мені грошей, і Петров винен мені грошей”. (3)

Цю фразу можна скоротити, зберігши колишній зміст:

“Сурков і Петров винні мені грошей”. (3)

Висловлювання (3) істинне лише тоді, коли істинні обидва висловлювання: (1) і (2). Якщо хоча б одне з них хибне, то результат теж хибний. Якщо обидва помилкові – теж.

Тобто, якщо Петров мені грошей не заборгував, а заборгував тільки Сурков, тоді вислів (3) не буде "напівправдою" або "напівложею", а буде просто брехнею.

"АБО"

Операція “АБО” застосовується до двох висловлювань. Її результат "істина", якщо хоча б один вислів істинний (а інакше "брехня"):

false АБО false = false
false АБО true = true
true АБО false = true
true АБО true = true

У цій операції бувають різні інші назви: "логічне АБО", "що включає АБО", "диз'юнкція", "логічне додавання". Для міжнародних позначень замість "АБО" пишуть "OR".
У природній мові цієї операції відповідає вставка спілки "або" між висловлюваннями, але... не завжди (див. нижче про операцію "XOR"). Наприклад:

"Я хочу попити". (1)
"Я хочу поїсти". (2)

Застосування операції “АБО” до висловів (1) та (2):

“Я хочу попити, чи хочу поїсти”. (3)

По-російськи звучить правильно, але кострубато, і цю фразу можна скоротити, зберігши колишній сенс:

“Я хочу попити чи поїсти”. (3)

Вислів (3) істинний тоді, коли істинно хоча б одне з висловлювань (1) і (2), а можна обидва. Якщо обидва висловлювання хибні, то результат теж хибний.

Тобто, якщо я хочу їсти, але не пити, тоді вислів (3) є істинним. Якщо я не проти і поїсти, і попити, висловлювання (3) теж є істинним. Хибно воно тоді, коли я не хочу ні того, ні іншого.

"XOR"

Операція “XOR” застосовується до двох висловлювань. Її результат "істина", якщо одно з висловлювань істинно (а інакше "брехня"):

false XOR false = false
false XOR true = true
true XOR false = true
true XOR true = false

У цій операції бувають різні інші назви: "Виключає АБО", "додавання за модулем 2", "логічне додавання за модулем 2". "XOR" - це міжнародне позначення, загальноприйнятого "російського" аналога немає.

У природній мові цієї операції відповідає вставка спілки "або" між висловлюваннями - так само, як у випадку з операцією "АБО". Наприклад:

“Я збираюся просити збільшення зарплати”. (1)
"Я спробую заощадити". (2)

Застосування операції “XOR” до висловів (1) та (2):

“Я збираюся просити збільшення зарплати або я спробую заощадити”. (3)

Скорочено:

"Я збираюся просити прибавки до зарплати або спробую заощадити". (3)

Висловлювання (3) істинно тоді, коли істинно одно з висловлювань (1) і (2). Якщо я не збираюся ні просити збільшення, ні економити, тоді фраза хибна. Також я мав на увазі, що не збираюся робити і те, й інше одночасно.

Зверніть увагу на різницю між операціями “АБО” та “XOR”. Вона полягає лише в останньому правилі:

true АБО true = true
true XOR true = false

У природній мові обидві операції зображуються одним і тим самим союзом "або". Це приклад неоднозначності природної мови. Якщо пам'ятаєте, омоніми та багатозначні слова можуть мати більше одного значення. Союз “або” саме такий: він має два можливі значення. Перше виражається логічною операцією "АБО", друге - логічною операцією "XOR".

В англійській мові існують ті ж проблеми: союз “or” має ті самі два значення. А ось стародавнім римлянам було простіше, тому що в латині є два різні слова: "vel" (операція "АБО") та "aut" (операція "XOR").

Оскільки різниця між операціями "АБО" і "XOR" невелика (всього одне останнє правило), то іноді ця різниця не має значення. Іноді у тому, що мають на увазі, можна здогадатися по інтонації, чи з контексту. Іноді визначити точний зміст так і не вдається.

Часто для того, щоб продемонструвати обмежені можливості одношарових персептронів при вирішенні завдань вдаються до розгляду так званої проблеми. XOR - виключає АБО.

Суть завдання полягають у наступному. Дана логічна функція XOR - що виключає АБО. Це функція від двох аргументів, кожен з яких може бути банкрутом або одиницею. Вона набуває значення , коли з аргументів дорівнює одиниці, але з обидва, інакше . Проблему можна проілюструвати за допомогою одношарової однонейронної системи з двома входами, що показана на малюнку нижче.

Позначимо один вхід через , а інший через , тоді всі їх можливі комбінації будуть складатися з чотирьох точок на площині. Таблиця нижче показує необхідний зв'язок між входами і виходом, де вхідні комбінації, які повинні давати нульовий вихід, позначені і одиничний вихід - і .

Крапки Значення Значення Необхідний вихід
0 0 0
1 0 1
0 1 1
1 1 0

Один нейрон із двома входами може сформувати вирішальну поверхню у вигляді довільної прямої. Щоб мережа реалізувала функцію XOR, задану таблицею вище, потрібно розташувати пряму те щоб точки були з одного боку прямий, а точки – з іншого. Спробувавши намалювати таку пряму малюнку нижче, переконуємося, що це неможливо. Це означає, що будь-які значення не приписувалися вагам і порога, одношарова нейронна мережа нездатна відтворити співвідношення між входом і виходом, необхідне представлення функції XOR.

Однак функція XOR легко формується вже двошаровою мережею, причому багатьма способами. Розглянемо один із таких способів. Модернізуємо мережу на малюнку, додавши ще один прихований шар нейронів:

Зазначимо, що ця мережа дана так, тобто. можна вважати, що вона вже навчена. Цифри над стрілками показують значення синаптичних терезів. Як функцію активації застосуємо функцію одиничного стрибка з порогом , що має наступний графік:

Тоді результат роботи такої нейронної мережі можна подати у вигляді наступної таблиці:

Крапки Значення Значення Необхідний вихід
0 0 0 0 0 0
1 0 1 1 0 1
0 1 1 0 1 1
1 1 0 0 0 0

Кожен із двох нейрон першого шару формує вирішальну поверхню у вигляді довільної прямої (ділить площину на дві півплощини), а нейрон вихідного шару об'єднує ці два рішення, утворюючи вирішальну поверхню у вигляді смуги, утвореної паралельними прямими нейронів першого шару:

Нейронна мережа, що використовується в цій статті для вирішення задачі XOR, є примітивною і не використовує всіх можливостей багатошарових мереж. Очевидно, що багатошарові нейронні мережі мають більшу потужність, що представляє, ніж одношарові, тільки в разі присутності нелінійності. А в цій мережі застосована гранична лінійна функція активації. Таку мережу не можна буде навчити, наприклад, застосувавши алгоритм зворотного розповсюдження помилки.