dc ( настольный калькулятор ) - кроссплатформенный калькулятор с обратной полировкой, который поддерживает арифметику произвольной точности . [1] Автор Роберт Моррис в то время как Bell Labs , [2] он является одним из старейшего Unix утилита, предшествующий даже изобретение языка программирования . Как и другие утилиты того же года выпуска, у него мощный набор функций, но лаконичный синтаксис. [3] [4] Традиционно программа калькулятора bc (с инфиксной нотацией ) была реализована поверх dc.
Автор (ы) оригинала | Роберт Моррис ( AT&T Bell Laboratories ) |
---|---|
Разработчики) | Различные разработчики с открытым исходным кодом и коммерческие разработчики |
Написано в | B |
Операционная система | Unix , Unix-подобный , Plan 9 |
Платформа | Кроссплатформенность |
Тип | Командование |
В этой статье приводится несколько примеров, чтобы дать общее представление о языке; для получения полного списка команд и синтаксиса следует обратиться к странице руководства для конкретной реализации.
История
dc - самый старый из сохранившихся языков Unix . Когда ее домашняя компания Bell Labs получила PDP-11 , dc, написанный на B, был первым языком, работающим на новом компьютере, даже до ассемблера. [5] Кен Томпсон считает, что программа dc была самой первой программой, написанной на этой машине. [2]
Основные операции
Чтобы умножить четыре и пять в постоянном токе (обратите внимание, что большая часть пробелов не обязательна):
$ cat << EOF> cal.txt 4 5 * p EOF$ dc cal.txt 20 $
Вы также можете получить результат с помощью команд:
$ echo "4 5 * p" | Округ Колумбия
или же
$ dc - 4 5 * pq 20$ dc 4 5 * p 20 q$ dc -e '4 5 * p'
Это означает «поместить четыре и пять в стек, затем с помощью оператора умножения извлечь два элемента из стека, умножить их и поместить результат обратно в стек». Затем p
команда используется для проверки (вывода на экран) верхнего элемента в стеке. Команда q
завершает запущенный экземпляр dc. Обратите внимание, что числа должны располагаться на расстоянии друг от друга, даже если этого не требуется для некоторых операторов.
Арифметическая точность изменяется с помощью команды k
, которая устанавливает количество дробных цифр (количество цифр , следующей за точкой ) , который будет использоваться для арифметических операций. Поскольку точность по умолчанию равна нулю, эта последовательность команд дает 0
в результате:
2 3 / п
Регулируя точность с помощью k
, можно получить произвольное количество десятичных знаков. Эта последовательность команд выводит .66666
.
5 тыс.2 3 / п
Оценить : ( v
вычисляет квадратный корень из вершины стека и _
используется для ввода отрицательного числа):
12 _3 4 ^ + 11 / v 22 -п
Чтобы поменять местами два верхних элемента стека, используйте r
команду. Чтобы продублировать верхний элемент, используйте d
команду.
Ввод, вывод
Чтобы прочитать строку из стандартного ввода , используйте ?
команду. Это будет оценивать строку, как если бы это была команда dc, поэтому необходимо, чтобы она была синтаксически правильной и потенциально представляла проблему безопасности, поскольку команда !
dc допускает выполнение произвольной команды.
Как упоминалось выше, p
будет напечатана верхняя часть стека с новой строкой после нее. n
вытолкнет верхнюю часть стека и выведет его без символа новой строки в конце. f
сбросит весь стек с одной записью в строке.
dc также поддерживает произвольные входные и выходные радиусы . Команда i
вытолкнет верхнюю часть стека и будет использовать ее в качестве базы ввода. Шестнадцатеричные цифры должны быть в верхнем регистре, чтобы избежать конфликтов с командами постоянного тока и ограничены AF. Команда o
делает то же самое для выходной базы, но имейте в виду, что входная база впоследствии повлияет на синтаксический анализ каждого числового значения, поэтому обычно рекомендуется сначала установить выходную базу. Поэтому 10o
устанавливает систему счисления вывода на текущую систему счисления ввода, но обычно не на 10 (десять). Тем не менее, Ao
сбрасывает выходную базу на 10 (десять), независимо от входной базы. Для того, чтобы считывать значения, то K
, I
и O
команды будут толкать текущую точность, входной и выходной десятичную системы счисления к верхней части стека.
Например, для преобразования из шестнадцатеричного в двоичный:
$ echo 16i2o DEADBEEFp | постоянный ток 11011110101011011011111011101111
Особенности языка
Регистры
В дополнение к этим основным арифметическим и стековым операциям, dc включает поддержку макросов , условных выражений и сохранение результатов для последующего извлечения.
Механизм, лежащий в основе макросов и условий, - это регистр , который в dc является местом хранения с одним символьным именем, которое может быть сохранено и получено из: sc
выталкивает верхнюю часть стека и сохраняет его в регистре c, а затем lc
помещает значение регистра c в стек. Например:
3 сбн 4 сбн * п
Регистры можно также рассматривать как вторичные стеки, поэтому значения могут быть задвинуты и совали между ними и основным стеком с использованием S
и L
команд.
Струны
Строковые значения заключаются в [
и ]
символах и могут быть в стеке и хранятся в регистрах. Команда a
преобразует младший байт числового значения в символ ASCII или, если вершина стека является строкой, она заменит его первым символом строки. Невозможно создать строки или выполнить манипуляции со строкой, кроме выполнения их с помощью x
команды или печати с помощью P
команды.
#
Персонаж начинает комментарий до конца строки.
Макросы
Затем макросы реализуются, позволяя регистрам и записям стека быть строками, а также числами. Строку можно напечатать, но также можно выполнить (т.е. обработать как последовательность команд постоянного тока). Так, например, мы можем сохранить макрос, чтобы добавить единицу, а затем умножить на 2 в регистре m:
[1 + 2 *] см
а затем (используя x
команду, выполняющую верхнюю часть стека) мы можем использовать это так:
3 лм xp
Условные
Наконец, мы можем использовать этот макро-механизм для создания условных выражений. Команда =r
извлечет два значения из стека и выполнит макрос, хранящийся в регистре, r
только если они равны. Таким образом, это напечатает строку equal
только в том случае, если верх стека равен 5:
[[равно] p] sm 5 = m
Другие условные являются >
, !>
, <
, !<
, !=
, который будет выполнять указанную макрокоманду , если два верхних значения на стеке больше, меньше или равно ( «не больше»), меньше чем, больше чем или равно ( "не менее "), и не равно соответственно.
Петли
Затем возможно выполнение цикла путем определения макроса, который (условно) повторно запускается. Простой факториал вершины стека может быть реализован как:
# F (x): вернуть x!# если x-1> 1# вернуть x * F (x-1)# иначе# return x[d1-d1
Команда 1Q
выйдет из макроса, что позволит досрочно вернуться. q
завершит работу с двух уровней макросов (и с самого dc, если в стеке вызовов меньше двух уровней). z
перед выполнением z
операции подтолкнет текущую глубину стека .
Примеры
Суммирование всего стека
Это реализуется с помощью макроса, хранящегося в регистре, a
который условно вызывает себя, выполняя каждый раз сложение, пока в стеке не останется только одно значение. z
Оператор используются для передачи количества записей в стеке на стек. Оператор сравнения >
извлекает из стека два значения при сравнении.
dc -e "1 2 4 8 16 100 0d [+ 2z> a] salaxp"
И результат 131.
Суммирование всех выражений постоянного тока в виде строк из файла
Чистое число является допустимым выражением постоянного тока, поэтому его можно использовать для суммирования файла, в котором каждая строка содержит одно число.
Это снова реализуется с помощью макроса, хранящегося в регистре, a
который условно вызывает себя, выполняя каждый раз сложение, пока в стеке не останется только одно значение.
файл кошки | dc -e "0d [? + 2z> a] salaxp"
?
Оператор считывает другую команду из входного потока. Если строка ввода содержит десятичное число, это значение добавляется в стек. Когда входной файл достигает конца файла, команда принимает значение NULL, и значение в стек не добавляется.
{ эхо "5" ; эхо «7» ; } | dc -e "0d [? + 2z> a] salaxp"
И результат 12.
Линии ввода также могут быть сложными командами постоянного тока.
{ echo "3 5 *" ; эхо «4 3 *» ; эхо "5dd ++" ; } | dc -e "0d [? + 2z> a] salaxp"
И результат 42.
Обратите внимание, что, поскольку dc поддерживает произвольную точность, нет необходимости беспокоиться о числовом переполнении или потере точности, независимо от того, сколько строк содержит входной поток, в отличие от аналогичного краткого решения в AWK .
Недостатками этого решения являются: цикл прекращает работу при обнаружении пустой строки во входном потоке (технически любой входной строке, которая не добавляет хотя бы одно числовое значение в стек); и для обработки отрицательных чисел ведущие экземпляры '-' для обозначения отрицательного знака должны быть изменены на '_' во входном потоке из-за нестандартного отрицательного знака dc. ?
Оператор постоянного тока не обеспечивает чистый способ различать чтение пустую строку от чтения конца файла.
Преобразование единиц
В качестве примера относительно простой программы на dc эта команда (в 1 строку):
dc -e '[[введите число (метры) или 0 для выхода] psj] sh [q] sz [lhx? d0 = z10k39.370079 * .5 + 0k12 ~ 1 / rn [футов] Pn [дюймы] P10Pdx ] dx '
преобразует расстояния из метров в футы и дюймы; большая часть этого связана с запросом ввода, печатью вывода в подходящем формате и циклическим преобразованием другого числа.
Наибольший общий делитель
В качестве примера, вот реализация алгоритма Евклида для поиска GCD :
dc -e '?? [dSarLa% d0 ]> # кратчайший
dc -e '[a =] P? [b =] P? [dSarLa% d0 ]> # более легкая для чтения версия
Факториал
Вычисление факториала входного значения,
dc -e '? [q] sQ [d1 = Qd1-lFx *] dsFxp'
Куинс в постоянном токе
Существуют также quines на языке программирования dc; программы, которые производят его исходный код в качестве вывода.
dc -e '[91Pn [dx] 93Pn] dx'dc -e '[91PP93P [dx] P] dx'
Печать всех простых чисел
echo '2p3p [dl! d2 + s!% 0 = @ l! l ^! <#] s # [s / 0ds ^] s @ [p] s & [ddvs ^ 3s! l # x0 <& 2 + lx] ds .x ' | Округ Колумбия
Эта программа была написана Мишелем Шарпантье. Он выводит последовательность простых чисел. Обратите внимание, что его можно сократить на один символ, что кажется минимальным решением.
echo '2p3p [dl! d2 + s!% 0 = @ l! l ^! <#] s # [0 * ds ^] s @ [p] s & [ddvs ^ 3s! l # x0 <& 2 + lx] ds .x ' | Округ Колумбия
Целочисленная факторизация
dc -e '[n =] P? [p] s2 [lip / dli% 0 = 1dvsr] s12sid2% 0 = 13sidvsr [dli% 0 = 1lrli2 + dsi!>.] ds.xd1 <2'
Эту программу также написал Мишель Шарпантье. [6]
Есть более короткий
dc -e "[n =] P? [lfp / dlf% 0 = Fdvsr] sF [dsf] sJdvsr2sf [dlf% 0 = Flfdd2% + 1 + sflr
и более быстрое решение (попытаться с 200-битным числом 2 200 -1 (входом 2 200^1-
)
dc -e "[n =] P? [lfp / dlf% 0 = Fdvsr] sFdvsr2sfd2% 0 = F3sfd3% 0 = F5sf [dlf% 0 = Flfd4 + sflr> M] sN [dlf% 0 = Flfd2 + sflr> N ] dsMx [p] sMd1
Обратите внимание, что последнее можно даже ускорить, если доступ к константе заменить доступом к регистру.
dc -e "[n =] P? [lfp / dlf% l0 = Fdvsr] sF2s2dvsr2sf4s4d2% 0 = F3sfd3% 0 = F5sf [dlf% l0 = Flfdl4 + sflr> M] sN [dlf% l0 = Flfdl2 + sfl ] dsMx [p] sMd1
Обмен ключами Диффи – Хеллмана
Более сложный пример использования dc, встроенного в сценарий Perl, выполняет обмен ключами Диффи – Хеллмана . Это было популярно как блок подписи среди шифропанков во время дебатов ITAR , где короткий сценарий мог быть запущен только с Perl и dc, вездесущими программами в Unix-подобных операционных системах: [7]
#! / usr / bin / perl - -export-a-crypto-system-sig Diffie-Hellman-2-lines ( $ g , $ e , $ m ) = @ARGV , $ m || die "$ 0 gen exp mod \ n" ; напечатать `echo" 16dio1 [d2% Sa2 / d0 dc`
Прокомментированная версия немного проще для понимания и показывает, как использовать циклы, условные выражения и q
команду для возврата из макроса. С версией dc для GNU |
команда может использоваться для модульного возведения в степень произвольной точности без необходимости написания функции X.
#! / usr / bin / perlmy ( $ g , $ e , $ m ) = map { "\ U $ _" } @ARGV ; die "$ 0 gen exp mod \ n", если не $ m ;print `echo $ g $ e $ m | dc -e ' # Шестнадцатеричный ввод и вывод 16dio # Считать m, e и g из стандартного ввода в одной строке ? SmSeSg# Функция z: вернуть g * вершину стека [lg *] sz# Функция Q: удалить верх стека и вернуть 1 [sb1q] sQ# Функция X (e): рекурсивно вычислить g ^ e% m # Это то же самое, что и Sm ^ Lm%, но обрабатывает произвольно большие показатели. # Стек при входе: e # Стек при выходе: g ^ e% m # Поскольку e может быть очень большим, здесь используется свойство g ^ e% m == # if (e == 0) # return 1 # x = (g ^ (e / 2)) ^ 2 # if (e% 2 == 1) # x * = g # return x% [ d 0 = Q # return 1 if e == 0 (в противном случае стек: e) d 2% Sa # Сохранить e% 2 в (стек: e) 2 / # вычислить e / 2 lXx # вызвать X (e / 2) d * # вычислить X (e / 2) ^ 2 La1 = z # умножить на g if e% 2 == 1 lm% # compute (g ^ e)% m ] SXle # Загрузить e из регистра lXx # вычислить g ^ e% m p # Распечатать результат '` ;
Смотрите также
- bc (язык программирования)
- Способы ввода калькулятора
- Калькуляторы HP
- Штабелеукладчик
Рекомендации
- ^ : калькулятор произвольной точности - Linux User Commands Manual
- ^ а б Брайан Керниган и Кен Томпсон. Ботанический восторг для любого посетителя Vintage Computer Fest 2019: Керниган берет интервью у Томпсона о Unix . YouTube. Событие происходит в 29:45 . Проверено 3 сентября 2019 года . CS1 maint: обескураженный параметр ( ссылка )
- ^ "Источники справочной страницы для 7-го издания Unix dc" .
- ^ Ричи, Деннис М. (сентябрь 1979 г.). «Эволюция системы разделения времени в Unix» . Архивировано из оригинала на 2010-05-06.
- ^ Макилрой, доктор медицины (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (технический отчет). CSTR. Bell Labs. 139. CS1 maint: обескураженный параметр ( ссылка )
- ^ «Advanced Bash-Scripting Guide, Глава 16, Пример 16-52 (Факторизация)» . Проверено 20 сентября 2020 .
- ^ Адам Бэк. «Диффи – Хеллман в 2-х строчках Perl» . Проверено 5 января 2009 года .
Внешние ссылки
- Пакет dc в репозиториях Debian GNU / Linux
- - Руководство программиста Plan 9 , том 1
- Собственный порт Windows для bc , который включает dc.
- dc встроен в веб-страницу