Из Википедии, бесплатной энциклопедии
  (Перенаправлено из Dc (Unix) )
Перейти к навигации Перейти к поиску

dc ( настольный калькулятор ) - кроссплатформенный калькулятор с обратной полировкой, который поддерживает арифметику произвольной точности . [1] Автор Роберт Моррис в то время как Bell Labs , [2] он является одним из старейшего Unix утилита, предшествующий даже изобретение языка программирования . Как и другие утилиты того же года выпуска, у него мощный набор функций, но лаконичный синтаксис. [3] [4] Традиционно программа калькулятора bcинфиксной нотацией ) была реализована поверх dc.

В этой статье приводится несколько примеров, чтобы дать общее представление о языке; для получения полного списка команд и синтаксиса следует обратиться к странице руководства для конкретной реализации.

История [ править ]

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 <F *] dsFxp

Команда 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 <a] dsax + p'  # кратчайший
dc -e '[a =] P? [b =] P? [dSarLa% d0 <a] dsax + [GCD:] Pp'  # более легкая для чтения версия

Факториал [ править ]

Вычисление факториала входного значения,

dc -e '? [q] sQ [d1 = Qd1-lFx *] dsFxp'

Куинс в DC [ править ]

Существуют также 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 <Jd1 <M] dsMx"

и более быстрое решение (попытаться с 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 <M "

Обратите внимание, что последнее можно даже ускорить, если доступ к константе заменить доступом к регистру.

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 <M "

Обмен ключами Диффи-Хеллмана [ править ]

Более сложный пример использования 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 <X + d * La1 = z \ U $ m% 0] SX $ e "[$ g *] \ EszlXx + p | 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
  • Штабелеукладчик

Ссылки [ править ]

  1. ^ dc(1) : калькулятор произвольной точности -  Linux User Commands Manual
  2. ^ а б Брайан Керниган и Кен Томпсон. Ботанический восторг для любого посетителя Vintage Computer Fest 2019: Керниган берет интервью у Томпсона о Unix . YouTube. Событие происходит в 29:45 . Проверено 3 сентября 2019 года . CS1 maint: обескураженный параметр ( ссылка )
  3. ^ "Источники справочной страницы для 7-го издания Unix dc" .
  4. Ричи, Деннис М. (сентябрь 1979 г.). «Эволюция системы разделения времени в Unix» . Архивировано из оригинала на 2010-05-06.
  5. Перейти ↑ McIlroy, MD (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (технический отчет). CSTR. Bell Labs. 139. CS1 maint: обескураженный параметр ( ссылка )
  6. ^ «Advanced Bash-Scripting Guide, Глава 16, Пример 16-52 (Факторизация)» . Проверено 20 сентября 2020 .
  7. ^ Адам Бэк. «Диффи – Хеллман в 2-х строчках Perl» . Проверено 5 января 2009 года .

Внешние ссылки [ править ]

  • Пакет dc в репозиториях Debian GNU / Linux
  • dc(1) -  Руководство программиста Plan 9 , том 1
  • Собственный порт Windows для bc , который включает dc.
  • dc встроен в веб-страницу