Два слова о трехзначной логике. Как работают троичные компьютеры и чем они интересны
Компьютеры, использующие троичную логику, придуманы уже давно. Еще в 1958 году Н. П. Брусенцов построил в МГУ первую опытную электронную троичную ЭВМ «Сетунь», а в 1973 году в США был создан Ternac — экспериментальный троичный эмулятор с арифметикой над 24-тритными целыми и 48-тритными действительными числами на двоичном компьютере Burroughs B1700. Может ли найти применение троичная логика в современных компьютерах? Крис Касперски считал, что это вполне возможно!
INFO
Эта статья была случайно обнаружена в пыльном и поросшем паутиной чулане редакции «Хакера» во время очередной генеральной уборки. Крис Касперски написал ее еще в 2003 году, но по определенным причинам материал не был опубликован. Сейчас мы решили исправить это. В своем эссе Крис пытался угадать следующий шаг развития вычислительной техники и обратил свой взгляд на троичную логику, которая, по его мнению, могла бы стать основой очередного этапа эволюции высоких технологий. Технические подробности, касающиеся принципов такой архитектуры, не утратили актуальности и сегодня.
Недалекое будущее… Гиганты микропроцессорной индустрии, как никогда, озабочены близостью физических ограничений тактовой частоты и степени интеграции, за которыми устойчивую работу чипов гарантировать станет просто невозможно. Производительности же имеющихся процессоров, даже таких спринтеров, как Pentium-XXX, хватит от силы года эдак на три, после чего потребитель начнет шибко нервничать и пинать конкурентов, которые, воспользовавшись всеобщим замешательством, получат шанс вырваться вперед. В ход идут всевозможные обходные приемы увеличения производительности — распараллеливание вычислений, упреждающие исполнение и загрузка команд.
Примечательно, что вышеперечисленные «новейшие» достижения не являются новейшими в буквальном понимании этого слова — в той или иной форме они были реализованы еще на ламповых машинах, нехило работающих в куда более тесных рамках физических ограничений. Быстродействие и количество электронных ламп в первых ЭВМ, конечно, не идет ни в какое сравнение с числом и резвостью транзисторов в современных компьютерах, но тем не менее факт остается фактом.
Постепенно все эти технологии мигрировали на платформу бытовых микропроцессоров, многократно увеличивая производительность, когда, казалось бы, все ресурсы уже на исходе. Так произошло и на этот раз… Едва начали раздаваться голоса, что конец золотого века микропроцессоров совсем близок и пора начинать перебираться на кластерные суперкомпьютеры, Intel «неожиданно» вспомнила о трехзначной логике.
Но что же это такое — трехзначная логика? И почему она сулит рекордное увеличение производительности при незначительном увеличении аппаратной сложности микропроцессора?
В сознании обывателя компьютеры настолько тесно связаны с логикой двоичной, битами и байтами, что представить что‑то другое большинство из нас просто не в состоянии. На самом деле трехзначная логика не нова, и впервые она была построена Лукасевичем в 1920 году! (Редактор заметил мимоходом, что трилогика в какой‑то мере использовалась в машине Бэббиджа, разработанной в XIX веке. Аристотель же обратил на нее внимание еще раньше. Однако математически осмыслена трилогика была лишь в середине XX века.) Как можно заключить из названия, в ней фигурирует уже не два терма: истина и ложь, а три — истина, ложь и фиг его знает. Покажем преимущества такого нововведения на простом примере.
Спроси первого встречного «В Багдаде сегодня был дождь?». С точки зрения двоичной логики прохожий должен ответить либо «да», либо «нет». Но ни тот ни другой ответ вопрошаемый дать не может, поскольку он вам не метеобюро. Ну не знает он! Да невозможно это сказать языком двоичной логики. Придется нам изменить вопрос. Для начала поинтересуемся — «знаете ли вы сегодня погоду в Багдаде?», и только в случае утвердительного ответа зададим следующий вопрос.
В троичной логике ответ на наш вопрос может быть получен сразу, то есть, говоря языком кибернетики, за один такт работы процессора вместо двух: прохожий ответит «А фиг его знает!». Раз уж мы заговорили о процессорах, рассмотрим простейшую программную задачу: сравним два числа — А и В. Очевидно, что возможны три варианта: A > B, A = B и A < B. В двоичном процессоре эту операцию приходится осуществлять за два прохода. Сначала выясняем, равны ли А и В. Если они окажутся неравны, то вторым заходом уточняем, А больше B или нет. Наглядно это показано на следующем рисунке.
Почему же компьютеры до сих пор строятся на двоичной основе? Причина заключается в аппаратной простоте двоичных вентилей. На определенном этапе развития вычислительной техники бинарная логика оказывалась намного выгоднее и экономичнее! Сегодня же все изменилось. Сложность вентилей стала менее критична их числа и количества соединений между ними. А производительность и вовсе важнее всего! Таким образом, троичные вентили выглядят весьма заманчивым фундаментом для современных компьютеров.
Останавливает лишь полная идеологическая несовместимость со старыми моделями. Все мы привыкли, что память компьютеров измеряется байтами, а сами байты состоят из восьми битов. В свою очередь, каждый бит может принимать значения ноль или один, соответствующие уровням сигнала на входе логического элемента. В троичной все не так. Там мерилом всего становится трит, принимающий значения –1, 0, +1, соответствующие уровням электрических сигналов — отрицательный сигнал, нет сигнала, положительный сигнал.
Шестерка тритов образует аналог байта — трайт. Между прочим, трайт имеет практически ту же аппаратную сложность, что и байт, но может хранить в себе не 28 = 256 целочисленных значений, а 36 = 729 (!). Если речь идет о динамической памяти, основанной на трехстабильных зарядовых элементах — конденсаторах, то трайт будет проще байта, поскольку использует шесть, а не восемь ячеек. Трехстабильные триггеры статической памяти будут в 1,5 раза сложнее, но за счет использования меньшего числа ячеек получаем, что 9/6 * 6/8 = 1,125, трайт статической памяти будет в грубом приближении не сложнее байта. Не правда ли, хороший способ получить больше оперативной памяти за ту же цену? А ее более компактное представление автоматически увеличит скорость обмена! Поэтому суммарный прирост производительности получается весьма и весьма впечатляющим.
Но на самом же деле это только надводная часть айсберга. Практический прирост производительности произойдет совсем по иным причинам. Чтобы понять это, вспомним теорию представления чисел. В любой книжке по информатике можно прочесть строки вроде «...представлением числа N назовем такое представление в позиционной системе исчисления с положительным целым основанием p, при котором запись числа в виде ряда цифр a1,a2,…an конечной длины n однозначно определяет значение этого числа по формуле»
N = a1pn – 1 + a2pn – 2 + an-1p1 + ... + an
Формула эта была прочно вбита в школьные годы учителями информатики или же немногим позже преподавателями — в студенческие. Но в исчислении с двоичным основанием никаких преград нет только на первый взгляд (правда, об этом пытались умалчивать, дабы не травмировать наше нежное юношеское сознание). Попробуйте представить по такой формуле отрицательное число. Черт возьми, оказывается, что это невозможно! В нашем арсенале только единицы и нули, дающие лишь множество положительных чисел и ноль в придачу.
Можно поразиться, как же ухитряется работать современный процессор. И в самом деле, как? Подумав некоторое время, мы придем к выводу, что можно «выделить» один бит для указания знака числа. Действительно, именно так и устроено подавляющее большинство современных процессоров. Например, в чипах Intel старший бит каждого числа может интерпретироваться как знаковый. «Может» следует читать и понимать в буквальном смысле. Отличить знаковое число от беззнакового аппаратно невозможно, так они имеют идентичные представления. Приходится «договариваться» об этом заранее.
В самом деле, посмотрим, что происходит, когда процессор пытается отнять от единицы двойку. Для начала процессор определяет, какое число из двух большее. В нашем случае 1 < 2, поэтому он меняет их местами, устанавливает флаг переноса, компенсируя изменение знака, и побитно отнимает от единицы разность этих чисел. Это же сколько микроопераций?! Хорошо, что хоть большую часть работы процессор берет на себя. Но немало забот выпадает и на долю программиста. Так, перед любыми операциями приходится заботиться о приведении типов и, что еще хуже, о проверке принадлежности операндов к заранее оговоренным границам. Например, если мы сложим байты +127 и +1, то получим –128 (!). Да, вот такая любопытная математика! Источник ошибки в том, что получившийся результат «заехал» в знаковый бит, от чего положительное 128 стало трактоваться как отрицательное 128. Подобных ошибок избежать очень и очень трудно. А многочисленные проверки, разбросанные по телу программы, отрицательно сказываются на компактности и производительности кода. Всех этих проблем нет в троичной логике. Трит может принимать значения –1, 0, +1, достаточные для представления как положительных, так и отрицательных чисел, безо всяких дополнительных ухищрений.
А троичная логика? Она позволяет решить любую задачу значительно меньшим числом операций. Выше мы уже рассматривали пример сравнения двух чисел, поэтому не будем повторяться. Покажем лишь открывающуюся возможность непротиворечивой обработки ошибок.
Рассмотрим простой пример: программа запросила у операционной системы немного памяти для собственных нужд, для чего вызвала соответствующую системную функцию. Операционная система покряхтела диском и вернула указатель на выделенный регион, который программа с радостью принялась использовать. Но ведь память‑то не бесконечна, и рано или поздно наступит момент, когда ее не хватит, и функция вернет в качестве указателя ноль — то есть попытается сигнализировать об ошибке. Вот именно, попытается! Если программист забудет проверить полученное значение, то Windows не останется ничего иного, как захлопнуть некорректно работающее приложение. Помнишь про случай с прохожим и погодой? Так и у всякой функции сперва приходится спрашивать «ты получила достоверный результат?» и если да, то «сообщи же его». Если программист забудет это сделать (или сделает неправильно), то возникает нештатная ситуация, когда функция не может подобрать слов, чтобы сказать: «Да не знаю я результата, ошибочка вышла!»
Сетунь
В 1957–1958 годах в стенах университета МГУ была построена практически единственная на сегодняшний день серийная троичная вычислительная машина. Это был компактный простой прототип нынешнего персонального компьютера, и он затем успешно трудился на многих предприятиях нашей необъятной страны от Ашхабада до Якутска. Выбор архитектуры был продиктован в первую очередь требованиями к стоимости и надежности ЭВМ, поэтому инженеры остановились на быстродействующих пороговых магнитных усилителях. Их тройственная природа позволяла достичь той же производительности меньшим (по сравнению с двоичной логикой) числом элементов.
Надежность экспериментального образца оказалась выше всяких похвал. С небольшими ремонтами (потребовавшимися из‑за заводских дефектов двух диодов и одного трансформатора) эта машина проработала свыше 15 лет, находясь в непрерывной эксплуатации в условиях резких перепадов температур и питающего напряжения.
Вычислительная мощность «Сетуни» была превосходной для машин того времени. Оперативная память, состоящая из 162 девятитритных ячеек, использовалась как кеш медленной внешней «барабанной» памяти. Учитывая, что код машинной операции умещался всего в трех тритах (что позволяло кодировать до 33 = 27 команд), даже такого маленького окна с лихвой хватало для размещения большинства подпрограмм и обрабатываемых ими данных, обращение к медленной внешней памяти сводилось к минимуму.
Самое приятное заключалась в том, что команды трехзначной логики позволяли решать задачи меньшим числом операций в сравнении со своими двоичными собратьями. Очевидно, это выливалось в экономию ресурсов, как оперативной памяти, так и процессорной мощности. В 1970 году была выпущена значительно усовершенствованная модель «Сетунь-70», с мультистековой поддержкой, обеспечивающей наилучшую производительность для вычислений с магазинной передачей промежуточных результатов (нечто похожее было в первых советских микрокалькуляторах, например в Б3-19М).
Но, увы, широкой популярности «Сетунь-70» так и не снискала, да и сама трилогика, несмотря на очевидные преимущества, была на долгие годы забыта, оставаясь лишь в теоретических разработках, ни одна из которых так и не была воплощена в законченную модель…
История трилогики
Трилогика была сформулирована Лукасевичем в 1920 году. В ней фигурировали термы «истина», «ложь» и «возможно». В качестве основных функций рассматривались отрицание и импликация. Производными от них считались конъюнкция и дизъюнкция. Спустя один год на свет появилась обобщенная n-ричная система Поста, которая оперировала двумя видами отрицания: циклического и симметричного.
N1([N1= [x] + 1 при [x] < n и [N1n] = 1) x]
N2 ( [N2x] = n – [x] + 1)
В булевой логике (n = 2) эти отрицания совпадают, но уже в трилогике (n = 3) по‑разному оперируют с этими логическими операциями.
В 1938 году была опубликована так называемая логика Бочвара, манипулирующая высказываниями двух типов — имеющими смысл (истинные или ложные) и бессмысленными. В ней поддерживалось три вида отрицаний: ¬a
— внешнее отрицание, ~a
— внутреннее отрицание и ã
— внутреннее отрицание внешнего утверждения.
Немногим позже, в 1946 году, необходимость описания процессов квантовой механики вынудила Рейхенбаха создать свою модель трилогики. Он ввел три вида отрицаний: циклическое, диаметральное и полное, различающиеся в основном их действием в отношении «неопределенности».
На заре развития вычислительной техники «сердцем» любой ЭВМ было реле — устройство, конструктивно состоящее из пары контактов, якоря и обмотки. Часто учебники информатики приводят реле в качестве «классического» двоичного элемента. На самом же деле существовали и пользовались большой популярностью так называемые поляризованные реле, замыкающие различные контакты в зависимости от полярности сигнала. Конструктивно они отличались лишь дополнительной группой контактов и механизмом балансировки якоря для удержания его в нейтральном положении.
Аналогично в современных компьютерах широко используется так называемая динамическая память, состоящая из множества конденсаторов, заряженное состояние которых трактуется логической единицей, напротив, разряженное — логическим нулем. На самом же деле каждая ячейка оперативной памяти компьютера — это троичный элемент, способный находиться в трех состояниях: –1 (отрицательный заряд), 0 (нет заряда), +1 (положительный заряд). Элементарная база большинства компьютеров троична по своей физической природе.
Трехстабильный триггер транзисторной логики гораздо сложнее своего двухстабильного собрата. Это и стало причиной доминирования двоичной логики на ранних этапах развития кремниевой цивилизации. Транзистор — двоичное устройство, обладающее двумя состояниями. «Открыт», если на базу подается положительный сигнал, и «Закрыт» в остальных случаях (речь идет только об элементах p-n-p, поскольку производство транзисторов n-p-n сопряжено со значительными технологическими трудностями).
Для эмуляции третьего состояния пришлось бы прибегать к сложным конструкциям, включающим в себя более одного транзистора, что поначалу сочли нерациональным. Сегодня же повышать производительность компьютеров увеличением тактовой частоты становится труднее, чем наращивать конструктивную сложность чипа.
ЗАКЛЮЧЕНИЕ
Можно ожидать, что программы, написанные с использованием троичной логики, будут содержать на порядок меньше ошибок и сократят сроки и затраты на предварительное тестирование. Но если все так хорошо, то почему же до сих пор не реализовано? Почему нам приходится воевать с глюками, изыскивать деньги на некстати подорожавшую оперативную память, когда якобы такие простые технические приемы позволяют этого избежать? Увы, троичная логика означает полную несовместимость с нашим мрачным битово‑байтным прошлым. Придется не только перекомпилировать все существующие наработки, но и создавать новые языки. Ведь си, паскаль, бейсик — все они прочно «привязаны» к двоичной логике. Как минимум еще одной очень серьезной проблемой является отсутствие полупроводниковых элементов с тремя стабильными состояниями и имеющих соизмеримую сложность с используемыми сегодня бинарными логическими вентилями.
Впрочем, новый процессор может эмулировать старый, выигрывая в производительности по причинам, указанным в начале статьи. В основном — благодаря ускоренному доступу к памяти, за счет ее компактного представления. Разумеется, и ядро, работающее на трилогике, в какой‑то степени увеличит производительность. Но остается открытым вопрос: появится ли поддержка трилогики для новых программ? Или же это будет глубоко скрыто внутри процессора?