Запустится ли это в Doom? Калькулятор, работающий на демонах / Хабр
Да
Десятки лет мы задавались вопросом: «Запустится ли на этом устройстве Doom?». Теперь мы наконец можем задать вопрос иначе: «Запустится ли этот код в Doom?»
В статье я продемонстрирую, что в Doom можно запускать любые конечные вычисления, если не учитывать ограничения размеров уровня. Я не доказал, что Doom полон по Тьюрингу (см. ниже).
Система отлично работает с «ванильным» релизом Doom 2 (v1.9) для MS-DOS. Никаких модов и тому подобного не требуется!
Я люблю подобные проекты. Меня вдохновляют эзотерические машины в других играх, например, в Minecraft и RollerCoaster Tycoon.
Исходный код
На случай, если кому-то интересно, как это работает, я опубликовал исходный код для создания карты:
https://github.com/nukep/doom-calculator
Связанные проекты
В комментариях мне сообщили, что были предприняты столь же впечатляющие попытки демонстрации вычислений в «ванильных» и «неванильных» движках!
- Игра «Жизнь» в BOOM: https://www. doomworld.com/forum/topic/131881-conways-game-of-life-in-boom/
- Doom в Doom: https://www.youtube.com/watch?v=c6hnQ1RKhbo (строго говоря, это эксплойт для исполнения произвольного кода, но всё равно круто)
- https://calabi-yau.space/blog/doom.html [перевод на Хабре] (логические вентили на основе лифтов из «ванильного» Doom.)
- Скрипт Voodoo: https://doomwiki.org/wiki/Voodoo_script (в основном BOOM и полы из конвейерных лент, однако с некоторыми возможностями «ванильного» Doom)
- Каскадный сумматор в BOOM: https://www.youtube.com/watch?v=pvji3DJNnqE, https://www.doomworld.com/idgames/levels/doom2/Ports/a-c/counter
NAND: универсальный логический вентиль
Моей первой попыткой исследования этой темы стала реализация вентиля NAND. Если я смог бы реализовать NAND, то смог бы реализовать что угодно.
NAND — это универсальный логический вентиль. Если вкратце, универсальные логические вентили можно соединять для создания всех возможных логических вентилей.
Таблица истинности NAND:
a | b | результат |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 1 |
Например, если a True и b True, то результат будет False.
NAND состоит из двух входов «включено/отключено» и одного выхода «включено/отключено». Если оба входа включены, то выход отключен. Если один из входов отключен, то выход включен.
Оказывается, можно комбинировать NAND (подавать выходы NAND на другие NAND) и создавать любые таблицы истинности. По сути, возможны любые конечные вычисления.
Чтобы разобраться, возможно ли это в Doom, я поэкспериментировал с редактором уровней Doom под названием SLADE. Мне достаточно было реализовать один вентиль NAND. После кучи экспериментов с лифтами, действиями, телепортами, переключателями, дверьми, монстрами и даже клонами игроков я нашёл простую и надёжную систему.
Бинарные диаграммы решений
Благодаря моим открытиям появилась система, способная реализовать любую булеву логику, описанную бинарной диаграммой решений.
Описанный выше NAND мы можем представить при помощи бинарной диаграммы решений.
Есть два узла для переменных a и b. Пунктирными линиями обозначено «отключено», или 0. Сплошными линиями обозначено «включено», или 1.
Если мы начинаем с «a» и «a» равно 0, то мы перейдём налево и придём к результату «1»; наша работа на этом завершена. Но если мы начнём с «a» и «a» равно 1, то перейдём направо и придём к «b». Если «b» равно 0, то результат равен «1». Если «b» равно 1, то результат равен «0».
Мы можем объединять NAND в цепочки и создавать ещё более сложные диаграммы. Но в данном случае я решил отказаться от простого объединения NAND, потому что это создаёт не очень эффективные диаграммы. На практике лучше создавать цепочки из других логических вентилей, например, AND, OR, XOR и так далее, или напрямую преобразовывать таблицу истинности в диаграмму.
В виде уровня Doom
Как выглядит вентиль NAND (a=1, b=0):
Бинарные диаграммы решений можно представить в Doom очень простым образом.
Узел превращается в небольшую комнату с двумя дверьми для 0 и 1. В корневых узлах находятся монстры.
Ребро узла становится телепортацией из телепорта за дверью в другую комнату, если эта дверь должна открыться.
Двери открываются активируемыми игроком переключателями. Также их могут открывать другие монстры (позже я объясню, почему это полезно).
Я принял решение обозначить 0 и 1 двумя переключателями. Поначалу кажется логичным иметь по одному переключателю для каждой переменной. Но мне показалось проще явно задавать переменную как 0 или 1, а для вычислений ждать, пока они будут заданы.
В готовом файле WAD калькулятора у меня есть отдельные переключатели для каждой цифры, но это всего лишь визуальная иллюзия. На самом деле это переменные, где каждые пары 0/1 разделены на две цифры: (0,1) -> a; (2,3) -> b; (4,5) -> c; (6,7) -> d; (8,9) -> e. Например, «6» означает «d=0», «7» означает «d=1».
Как складывать числа при помощи этой системы?
Может быть сложно представить, как телепортирующиеся в разные места монстры способны обозначать сложение. Это одна из тех задач, в которых проще разбираться, двигаясь помаленьку и снизу вверх.
Мы прошли путь от NAND до бинарных диаграмм решений. Теперь давайте попробуем сложить две двоичные цифры.
Существует две двоичные цифры: 0 и 1.
Правила сложения двоичных цифр таковы:
a | b | перенос | сумма | иными словами |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 + 0 = 0 |
0 | 1 | 0 | 1 | 0 + 1 = 1 |
1 | 0 | 0 | 1 | 1 + 0 = 1 |
1 | 1 | 1 | 0 | 1 + 1 = 0, перенос 1 |
Мы также можем решить интерпретировать эти правила как таблицу истинности. Это называется полусумматор.
Полусумматор — эквивалент логических вентилей:
- перенос = a and b
- сумма = a xor b
Это отлично подходит для сложения двух двоичных цифр… но нам нужно складывать числа побольше!
Мы вполне можем скомбинировать множество полусумматоров, чтобы создать суммирующую машину. Но на практике эффективнее реализовать специальную логику для сложения 3 битов: двух чисел и бита переноса. Это называется полным сумматором.
Например, с такими тремя членами: «1 + 0 + 1 = 0, перенос 1».
Полный сумматор эквивалентен таким логическим вентилям:
- перенос = (a and b) or (b and c) or (c and a)
- сумма = a xor b xor c
Теперь мы можем объединить в цепочку полусумматор со множеством полных сумматоров, чтобы создать n-битный сумматор (где n — нужное нам количество битов). Это работает точно так же, как обычное сложение: складываем два числа, затем переносим 1 в левую пару цифр, потом складываем их, и так далее.
Нас интересует сложение чисел от 0 до 9. Как нам это описать? Оказывается, для описания чисел от 0 до 9 нам нужно не менее 4 двоичных цифр (где 0 = 0000, а 9 = 1001). Следовательно, мы используем 4-битный сумматор.
Однако у нас есть серьёзная проблема: нам нужно отображать результаты по основанию 10, а не в двоичном или шестнадцатеричном виде.
Решением будет преобразование результатов 4-битного двоичного сумматора. Получившаяся логика называется BCD adder (двоично-десятичным сумматором).
Если результат больше 9, то мы прибавляем 6. Применяем деление на 8 с остатком. В конце устанавливаем флаг переноса.
Таким образом, операция вида «9 + 5 = 14» даст нам «1001 + 0101 = 0100, перенос 1».
Псевдокод BCD adder:
# 4-битное двоичное сложение # результат - это бит переноса, а затем биты суммы zc,z3,z2,z1,z0 = cin + (a3,a2,a1,a0) + (b3,b2,b1,b0) # если результат 4-битного двоичного сумматора > 9, задаём бит переноса "cout" cout = zc or (z3 and z2) or (z3 and z1) # Если результат 4-битного двоичного сложения > 9, прибавляем 6 (0110) и делим на 8 с остатком s0 = z0 cc1, s1 = z1 + cout # полусумматор (2 члена) cc2, s2 = cc1 + z2 + cout # полный сумматор (3 члена) _, s3 = cc2 + z3 # полусумматор (2 члена)
Получившаяся бинарная диаграмма решений (неоптимизированная) выглядит следующим образом (входные переменные выделены синим, временные переменные — жёлтым):
Полная версия находится здесь
Подведём итог: представленная выше диаграмма описывает сложение двух цифр от 0 до 9 и получение цифры от 0 до 9 с переносом.
Для упрощения этой схемы есть множество разных деревьев. Некоторые из них задают переменные, единственное предназначение которых — быть использованными в последующих деревьях.
Чтобы визуализировать приведённую выше диаграмму с монстрами и телепортами, в вершине каждого дерева (корневом узле) будет находиться монстр. Все некорневые узлы будут точками перемещения для монстров. Всего есть 14 монстров, по одному для 14 деревьев.
Связывание выходов с переменными
Чтобы собрать диаграммы из множества мелких диаграмм, полезно будет сказать: «этот выход должен быть переменной». Возможно, вы заметили, что BCD adder зависит от этого.
Для уровня Doom это обозначает следующее: «проходящий через телепорт монстр должен открывать другие двери».
В «ванильном» Doom монстры не могут активировать переключатели или дистанционно открываемые двери. Поэтому я решил использовать особенность движка Doom. Все двери ассоциированы с сектором. Если дверь имеет общий сектор с другой дверью, то эти две двери всегда будут открываться и закрываться вместе. Монстры не могут открывать далёкие двери, однако могут открывать локальные двери. Если эта локальная дверь имеет общий сектор с другими дверьми, то монстры могут дистанционно открывать двери!
Поэтому вместо конечной точки монстр телепортируется в комнату с единственной дверью, которую он вынужден держать открытой. Эта дверь имеет общий сектор с одной или несколькими другими дверьми, которые поэтому откроются.
У этой особенности есть различные ограничения. Например, общие секторы должны иметь точно такие же текстуры пола и потолка, а также высоты. К счастью, это не влияет на функциональность, поэтому устраивает нас. Многие редакторы уровней Doom (например, SLADE) при редактировании отдельных полигонов пытаются сделать секторы «необщими», поэтому если вы захотите позже отредактировать карту, это нужно делать внимательно.
Отображение цифр
Я решил, что просто показывать двоичные значения было бы скучно. Мне нужно проделать весь путь и показывать настоящие числа.
Для отображения цифр я создал таблицы истинности для каждого пикселя дисплея.
Число от 0 до 9 можно представить 4 двоичными цифрами (0/1). Например, я возьму пиксель в строке 1, столбце 2 и покажу его таблицу истинности. Учтите, что для удобства чтения я свёл 4 входа в один столбец таблицы.
биты 3210 | выход |
---|---|
0000 (0) | 1 |
0001 (1) | 0 |
0010 (2) | 1 |
0011 (3) | 1 |
0100 (4) | 0 |
0101 (5) | 1 |
0110 (6) | 1 |
0111 (7) | 1 |
1000 (8) | 1 |
1001 (9) | 1 |
1010 (10) | undefined |
1011 (11) | undefined |
1100 (12) | undefined |
1101 (13) | undefined |
1110 (14) | undefined |
1111 (15) | undefined |
Её можно выразить как следующую бинарную диаграмму решений:
Двоичные значения с 10 по 15 не определены (undefined), потому что мы не ожидаем их встретить. Написанный мной алгоритм генерации диаграммы назначает произвольные выходы значениям с 10 по 15, в зависимости от которых происходит дальнейшая оптимизация диаграммы. (На практике для цифр «bit 3=1» просто означает 8 и 9. Если 8 и 9 имеют одинаковый результат, то мы знаем результат для «bit 3=1».)
Генерация уровня при помощи кода
Я не создавал сумматор в редакторе уровней. Ручное создание было бы чрезвычайно монотонным и ненадёжным процессом, поэтому я написал код.
Код генерации файла WAD написан на языке программирования Clojure.
Lisp подчиняется философии «код — это данные», поэтому древовидные структуры в виде кода писать получается достаточно интуитивно.
Мы можем описать вентиль NAND при помощи синтаксиса Lisp.
;; a NAND b: (a 1 (b 1 0))
Это древовидная структура данных. Она состоит из вложенных списков в виде (variable on-0 on-1)
.
Также это можно визуализировать как идущее вбок дерево, считываемое слева направо:
Но самое замечательное в том, что всё это одновременно работает и как код. Если a и b — это функции, возвращающие левую или правую форму, то можно действительно это выполнить и получить результат!
;; функция, возвращающая right (defn a [left right] right) ;; функция, возвращающая left (defn b [left right] left) (a 1 (b 1 0)) ;; returns 1
В очень кратком синтаксисе мы можем реализовать более сложную логику:
;; Полный сумматор ;; Дерево 1: бит суммы (cin (a (b 0 1) (b 1 0)) (a (b 1 0) (b 0 1))) ;; Дерево 2: бит переноса (cin (a 0 (b 0 1)) (a (b 0 1) 1))
Реализация этих функций зависит от того, что вам нужно сделать. В данном случае мы генерируем уровни, поэтому все функции для переменных создают список смежных вершин графа, где узлы идентифицируются числами с автоматическим инкрементом.
Однако многие бинарные диаграммы решений представляют собой не деревья, а графы. Узлы в бинарной диаграмме решений могут иметь несколько родителей. Как же выразить графы?
На самом деле эта задача обманчиво проста. Если мы констатируем, что все деревья являются неизменяемыми математическими значениями, то сможем сказать, являются ли два дерева эквивалентными. Избыточные эквивалентные деревья удаляются, по сути, создавая графы в памяти.
Оптимизация деревьев
Для оптимизации деревьев я использую различные методики:
- Если дерево «a» указывает на деревья «b» и «c», и при этом b = c, то a = b = c
- Если переменная «v» используется в другом месте только один раз, находится в корневом дереве «a», и дерево указывает на деревья «b» и «c», то v.0 = b и v.1 = c
- Удаляем все деревья, которые в конечном итоге не влияют на выходы (где могут появиться монстры).
Оптимизацию 3 я решил реализовать при помощи матриц смежности. 2 + …, что даёт нам окончательный результат всех достижимых деревьев. Код для этого находится здесь: https://github.com/nukep/doom-calculator/blob/e3dd9c0c6de19830febd0d1f845befca70ad632d/src/doomcalc/tree.clj#L217
Отрисовка уровня
Уровни Doom хранятся в формате WAD. Согласно «Библии Doom» Тома Холла, WAD официально расшифровывается как «Where’s All the Data?».
Несмотря на то, что игра трёхмерная, карты Doom существуют на плоской декартовой плоскости. Высота создаётся присвоением полигональным фигурам на карте переменных высот полов и потолков (в Doom эти фигуры называются «секторами»).
К счастью, WAD — очень простой формат файлов, поэтому мне удалось с нуля написать программу создания WAD.
Так как уровни задаются в 2D, процедуры отрисовки уровня схожи с функциями отрисовки векторной графики, например, «нарисовать линию из a в b».
Обходим особенности «ванильного» Doom
Я заметил, что открывающие двери монстры работали в GZDoom, но иногда не работали в Chocolate Doom или в «ванильном» Doom для MS-DOS.
Чтобы разобраться, почему так происходит, я поступил как любой разумный человек: заглянул в исходный код Doom. (Конечно, всё, что я делал до этого, было абсолютно разумным.)
Официальный релиз исходного кода Doom компании id Software можно найти здесь: https://github.com/id-Software/DOOM.
При помощи Ctrl+F я поискал ключевые слова наподобие «open» и «door», в конечном итоге обнаружив код, где монстры пытаются самостоятельно открывать двери.
Я начал со следующей функции P_Move()
: https://github.com/id-Software/DOOM/blob/77735c3ff0772609e9c8d29e3ce2ab42ff54d20b/linuxdoom-1.10/p_enemy.c#L272.
В виде псевдокода процедура монстров, открывающих двери, выглядит так. Множество не относящихся к делу подробностей я вырезал:
# p_enemy.c: P_Move() def P_Move(actor): # Направление - это единичный вектор. 1 из 8 возможных направлений (с инкрементом в 45 градусов). try_position = actor.position + actor.speed*actor.direction actor_moved = False # p_map. c: P_TryMove(), P_CheckPosition() spechit = [] for each line within the actor radius from try_position: # p_map.c: PITCheckLine() # Примечание: линии разделены на blockmap (секции уровня 128x128). # Blockmap проверяются снизу вверх, а затем слева направо. (буквой N) if line has no back face: break if line blocks players or monsters: break if line has a special action: spechit.push(line) if loop did not break: if new floor is within 24 units (not too high or low): if actor can fit in the room: move the actor to try_position actor_moved = True for each line in spechit, in reverse order: if actor walks over line: trigger line spechit = [] if not actor_moved: for each line in spechit, in reverse order: use line spechit = []
Вот самые важные открытия:
- Игра ищет все особые линии в радиусе действия монстра, от которых монстр пытается двигаться (а не оттуда, где находится).
- Существует глобальный массив, добавляемый с особыми линиями «spechit». Может храниться до восьми таких линий, но игра не останавливается на восьми (возможно, переполнение буфера).
- Поиск по blockmap выполняется начиная со столбцов (снизу вверх, затем слева направо)
- Процедура итерации прекращается, если у любой из линий в радиусе действия монстра имеется включённый флаг «block players» или «block players and monsters».
- Также она прекращается, если находит стену без обратной грани (например, внешнюю грань карты).
Чтобы позволить монстрам открыть дверь, мы используем следующие практические ограничения:
- В пределах радиуса+скорости монстра нет линий с флагами «block players/monsters» (для розового демона: 30.0 + 10.0 = 40.0 единиц)
- В пределах радиуса+скорости монстра (40.0 единиц) нет односторонних линий (например, периметра карты)
- Все двери, которые не нужно открывать монстрам, должны находиться вне пределов радиуса+скорости монстра (40. 0 единиц)
В оригинале статьи есть интерактивное демо, симулирующее дисплей цифр.
Оно полностью соответствует тому, что происходит на карте Doom.
Значит ли это, что Doom полон по Тьюрингу?
Мои наблюдения этого не подтверждают. Однако это может быть потрясающим утверждением, ведь оно означало бы, что мы можем запустить что угодно, включая и сам Doom (конечно же, если устранить ограничения карт и памяти).
Проект «Doom-in-Doom» использует эксплойт с исполнением произвольного кода для запуска Doom в Doom: https://www.youtube.com/watch?v=c6hnQ1RKhbo. Он невероятно впечатляет! Также стоит заметить, что для выполнения логики он использует не механизмы Doom, а сразу спускается на уровень оборудования и выполняет машинный код (и его точно нельзя портировать за пределы «ванильного» или Chocolate Doom!).
Нужно уточнить, что Doom определённо функционально полон. То есть если бы мы устранили все технические ограничения, то он бы мог выполнять все логические вентили.
Чтобы Doom был полон по Тьюрингу, он должен позволять выполнять какую-нибудь конструкцию неограниченного цикла.
Моя система неполна по Тьюрингу, потому что в ней нет неограниченных циклов и состояния. Когда монстры добираются до своей конечной точки, они остаются там навечно. Нет никакого способа «сбросить» монстров. Возможно, это можно сделать селективным повторным вызовом (телепортацией) определённых монстров, чтобы они могли использоваться в качестве входов для следующей итерации вычислений. Вероятно, это был бы следующий этап доказательства того, является ли Doom полным по Тьюрингу.
Оптимистично ли я настроен относительно его полноты по Тьюрингу? Ещё как! Но чтобы судить об этом с уверенностью, нужно проделать дополнительную работу.
Если в конечном итоге окажется, что он полон по Тьюрингу, то мы сможем доказать полноту по Тьюрингу, реализовав что-то, обладающее таким свойством. Если мы сможем реализовать конвеевскую игру «Жизнь» или правило 110, то это будет достаточным доказательством. (Мне нравится идея игры «Жизнь» из-за ироничности реализации «Жизни» в видеоигре, посвящённой убийству демонов).
Дополнение: игра «Жизнь» работает в Doom! Для её запуска нужен более новый движок, совместимый с BOOM: https://www.doomworld.com/forum/topic/131881-conways-game-of-life-in-boom/.
Другие люди тоже реализовали логические вентили в Doom!
Я с перерывами работал над этим проектом в течение двух с лишним лет. За это время меня обогнал Джаред Канделариа! Он даже придумал похожее название для статьи.
https://calabi-yau.space/blog/doom.html [перевод на Хабре]
Его методика отличалась от моей, в ней задействованы лифты и синхронизация с таймингами этих лифтов. Джаред утверждает, что его система полна по Тьюрингу, однако у меня есть в этом сомнения (по тем же причинам, по которым полной по Тьюрингу не является моя система).
Скачать WAD
Запускать карту я рекомендую в современном порте исходников наподобие GZDoom.
Также я выложил версию WAD, работающую в релизе Doom 2 (v1.9) для MS-DOS, однако она имеет множество графических глитчей. Впрочем, она функциональна и обладает всеми ограничениями «ванильного» Doom!
Вот она! https://github.com/nukep/doom-calculator/releases/
§3.2. Алгебра логики | Урок 63 часть 11
Планирование уроков на учебный год (по учебнику Н.Д. Угриновича, профильный уровень)
Главная | Информатика и информационно-коммуникационные технологии | Планирование уроков и материалы к урокам | 10 классы | Планирование уроков на учебный год (по учебнику Н.Д. Угриновича, профильный уровень) | §3.2. Алгебра логики
Содержание урока
3.2.1. Логическое умножение, сложение и отрицание3. 2.2. Логические выраженияЛогические выражения
Практическое задание «Определение истинности логического выражения»
Задание «Таблица истинности логического выражения»
Равносильные логические выражения
Контрольные вопросы. Задания. Компьютерный практикум
3.2.3. Логические функции3.2.4. Логические законы и правила преобразования логических выражений3.2.5. Решение логических задачПрактическое задание «Определение истинности логического выражения»
Определить истинность логического выражения (A ∨ B) & (А ∨ B) с использованием таблиц истинности базовых логических операций и с использованием программного калькулятора.
Подставим в логическое выражение значения логических переменных и, используя таблицы истинности базовых логических операций, получим значение логического выражения:
(A ∨ B) & (А ∨ B) = (0 v 1) & (1 v 0) = 1 & 1 = 1.
Определение истинности логического выражения т с использованием компьютерного калькулятора
1. Запустить компьютерный калькулятор NumLock Calculator.
2. Установить удобный вид калькулятора командой [Вид калъкулятора-Программистский].
3. Ввести логическое выражение, подставив в него значения логических переменных.
4. Нажать на клавиатуре клавишу {Enter}, получим значение логического выражения (рис. 3.7), которое совпадает со значением, вычисленным с использованием таблиц истинности.
Рис. 3.7. Определение истинности логического выражения с использованием калькулятора
Построение таблиц истинности логических выражений
Для каждого логического выражения можно построить таблицу истинности, которая определяет его истинность или ложность при всех возможных комбинациях исходных значений логических переменных.
При построении таблиц истинности целесообразно руководствоваться определенной последовательностью действий.
Во-первых, необходимо определить количество строк в таблице истинности, которое равно количеству возможных комбинаций значений логических переменных, входящих в логическое выражение. Если количество логических переменных n, то:
Количество строк = 2n.
В нашем случае логическое выражение (A ∨ B) & (А ∨ B) имеет две переменные и, следовательно, количество строк в таблице истинности должно быть равно:
Количество строк = 2n = 22 = 4.
Во-вторых, необходимо определить количество столбцов в таблице истинности, которое равно количеству логических переменных плюс количество логических операций (при желании можно сократить количество столбцов, объединив несколько логических операций в одном столбце). В нашем случае количество переменных равно двум, а количество логических операций равно пяти, т. е. количество столбцов таблицы истинности равно:
Количество столбцов = 2 + 5 = 7.
В-третьих, необходимо построить таблицу истинности с указанным количеством строк и столбцов, обозначить столбцы и внести все возможные наборы значений логических переменных. Наборы входных переменных, во избежание ошибок, рекомендуют вводить следующим образом:
1) разделить столбец значений первой переменной пополам и заполнить верхнюю часть колонки нулями, а нижнюю — единицами;
2) разделить столбец значений второй переменной на четыре части и заполнить четверти чередующимися группами нулей и единиц, начиная с группы нулей;
3) продолжать деление слолбцов значений последующих переменных на 8, 16 и т. д. частей и заполнение их группами нулей или единиц до тех пор, пока группа нулей (единиц) не будет состоять из одного символа.
В-четвертых, необходимо заполнить таблицу истинности по столбцам, выполняя базовые логические операции в необходимой последовательности и в соответствии с их таблицами истинности. Теперь мы можем определить значение логической функции для любого набора значений логических переменных.
Построим таблицу истинности для рассмотренного логического выражения (табл. 3.4).
Таблица 3.4. Таблица истинности логического выражения (A ∨ B) & (А ∨ B)
Следующая страница Задание «Таблица истинности логического выражения»
Cкачать материалы урока
Генератор таблиц истинности
· Темы GitHub · GitHub
Вот 39 публичных репозиториев соответствует этой теме…
чиколучио / генератор таблицы истинности
Спонсор Звезда 56Дайдр / таблица истинности
Звезда 37Мерлин04 / truetable.
es Звезда 18ксехот / Генератор таблиц правды
Звезда 14чираг-какар / PyAutomation
Звезда 10солончак / правда_таблицы
Звезда 64g3nt81lly / логика-утилита
Звезда 5чиколучио / упражнения-логика-ttg
Спонсор Звезда 4ShaanКодирование / Логическое выражение-решатель
Звезда 3ЮссефАли11997 / Генератор таблиц истинности
Звезда 3КомпрософтГенеральный директор / Таблица правды
Звезда 3мохамедмашаал / Генератор таблиц истинности
Звезда 2Лиам Грэм / правдивый
Звезда 2леомарига / pyTruthTable
Звезда 2аминбейги / генератор таблицы истинности
Звезда 1Дереизи / Пропозициональный калькулятор
Звезда 1МаркосШале / логический калькулятор
Звезда 1БилавалАхмед0900 / ПредложениеТаблица
Звезда 1HoloInJava / Генератор таблиц правды
Звезда 1Эфу-Дев / таблица правды реакции
Звезда 1Улучшить эту страницу
Добавьте описание, изображение и ссылки на генератор таблицы истинности страницу темы, чтобы разработчикам было легче узнать о ней.
Курировать эту тему
Добавьте эту тему в свой репозиторий
Чтобы связать ваш репозиторий с генератор таблицы истинности тему, перейдите на целевую страницу репозитория и выберите «управление темами».
Узнать больше
Правда об автокредитных калькуляторах
Как получить наиболее точную информацию из онлайн-калькуляторов.
Аарон Миллер 17 августа 2021 г.
Первоначально опубликовано 2 апреля 2018 г. Попытка договориться с дилером на основе ежемесячных платежей является распространенной ошибкой, но все же важно иметь общее представление о том, сколько вы можете рассчитывать платить каждый месяц. По данным Google, это одна из причин, по которой люди чаще ищут «калькулятор автокредитования», чем просто «автокредит». Если вы ищете новую или подержанную машину, скорее всего, вы уже сталкивались с каким-нибудь калькулятором автокредитов. Существует множество вариаций, но на самом базовом уровне все они делают похожие вещи. И они могут быть настолько точными, насколько точны введенные вами числа. В зависимости от того, какой калькулятор вы используете, он может выдать множество важных чисел. Большинство даст вам некоторую оценку ежемесячного платежа. Некоторые могут работать в обратном направлении и пытаться сообщить вам максимальную цену, которую вы можете себе позволить, исходя из того, что вы готовы платить каждый месяц. Некоторые даже пытаются учитывать налог с продаж. Однако есть две важные части информации, которые калькуляторы склонны оставлять вам: Существует очень большая вероятность того, что вы еще не знаете, на какую годовую процентную ставку вы будете претендовать. Некоторые калькуляторы рекомендуют использовать ставку по умолчанию (или автоматически сделать это за вас), но эта ставка часто доступна только для людей с исключительной кредитоспособностью. Это очень важно, потому что, не зная вашего годового дохода, ни один калькулятор не даст вам точного ответа. Ситуация становится еще более сложной, когда вы пытаетесь выяснить, можете ли вы вообще получить одобрение такого кредита. Возможно, вам будет удобно взять на себя автомобиль за 37 000 долларов, но это не значит, что кредитор позволит вам одолжить такую сумму. Проще говоря, калькуляторы на самом деле не дают вам ответов, если вы не знаете точно, на какие условия вы можете претендовать. Однако есть способ найти эту информацию без подачи заявки на финансирование. Здесь в игру вступает предварительная квалификация; примерно за то же время, что и на большинстве калькуляторов, вы можете получить действительные числа. Если вы по-прежнему чувствуете необходимость, вы можете использовать свои новые, более точные числа предварительного квалификационного отбора, чтобы улучшить результаты предпочитаемого вами калькулятора. Многие кредитные компании предпочли бы, чтобы вы сначала официально подали заявку на финансирование, а потом получили ответы, но это связано с своего рода «жесткой тягой», которая может оказать долгосрочное влияние на ваш кредит история (особенно если вы решили не покупать машину прямо сейчас). Избегание именно этого сценария является одной из основных причин для предварительного отбора на получение кредита. Вот почему несколько разных кредиторов — гм, да, включая Capital One — позволят вам сделать это онлайн. При предварительном отборе вы вводите некоторую основную информацию: имя, номер телефона, номер социального страхования и т. д. Это та информация, которая понадобится почти любому кредитору при принятии решения о том, способны ли вы погасить кредит. Когда вы закончите, у вас будет реалистичный набор показателей APR и суммы кредита, на которых можно основывать свои расчеты, не нанося потенциального ущерба вашему кредитному рейтингу (поскольку это считается только так называемым «мягким запросом»). Несмотря на присущие им ограничения, автокредитные калькуляторы все еще имеют свои достоинства. При использовании в сочетании с числами, полученными в результате предварительной квалификации, калькуляторы могут быть невероятно полезными инструментами. Они также на удивление забавны, особенно если вам нравятся гипотетики: Насколько больше вы сможете позволить себе машину, если просто уберете кабельное телевидение из своего бюджета? Или если вы реже обедаете вне дома? Что, если бы вы сделали и то, и другое!? Возможности столь же открыты, как ваше воображение. Если вы начинаете с точных цифр, хороший калькулятор автокредита может помочь лучше понять нерешенный вопрос. Например, если автомобиль, который вы рассматриваете, стоит 30 000 долларов США, сколько будет стоить ваш ежемесячный платеж? Как изменится этот платеж, если вместо этого вы финансируете на 48 или 60 месяцев? Это очень важные вопросы, на которые нужно ответить, прежде чем ступить на участок дилера. Использование калькулятора и предварительная квалификация – два отличных способа получить ответы на свои вопросы. TAGSFeaturedFinancingCalculatorsPre-Qualify Этот сайт предназначен только для образовательных целей. Перечисленные третьи лица не связаны с Capital One и несут единоличную ответственность за свое мнение, продукты и услуги. Capital One не предоставляет, не поддерживает и не гарантирует какие-либо сторонние продукты, услуги, информацию или рекомендации, перечисленные выше. Информация, представленная в этой статье, считается точной на момент публикации, но может быть изменена. Показанные изображения предназначены только для иллюстрации и могут не соответствовать продукту. Материалы, представленные на этом сайте, не предназначены для предоставления юридических, инвестиционных или финансовых рекомендаций или указания на доступность или пригодность какого-либо продукта или услуги Capital One для ваших уникальных обстоятельств. Для получения конкретных советов о ваших уникальных обстоятельствах вы можете проконсультироваться с квалифицированным специалистом. КАЛЬКУЛЯТОРЫ ОТЛИЧНЫЕ, НО НЕ СОВЕРШЕННЫЕ
РАЗНИЦА МЕЖДУ ПРЕДВАРИТЕЛЬНОЙ КВАЛИФИКАЦИЕЙ И ПОДАЧЕЙ ЗАЯВЛЕНИЯ ОГРОМНА
ЕСТЬ ВАЖНЫЕ И ИНТЕРЕСНЫЕ ПРИЧИНЫ ИСПОЛЬЗОВАТЬ АВТОКРЕДИТНЫЙ КАЛЬКУЛЯТОР