dc (компьютерная программа) - dc (computer program)

редактировать
dc
Оригинальный автор (ы) Роберт Моррис. (ATT Bell Laboratories )
Разработчик (и) Различные разработчики с открытым исходным кодом и коммерческие разработчики
Написано наB
Операционной системе Unix, Unix-подобный, Plan 9
Платформа Кросс-платформенный
Тип Команда

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

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

Содержание
  • 1 История
  • 2 Основные операции
  • 3 Ввод / вывод
  • 4 Языковые функции
    • 4.1 Регистры
    • 4.2 Строки
    • 4.3 Макросы
    • 4.4 Условные выражения
    • 4.5 Циклы
  • 5 Примеры
    • 5.1 Суммирование всего стека
    • 5.2 Суммирование всех выражений постоянного тока в виде строк из файла
    • 5.3 Преобразование единиц
    • 5.4 Наибольший общий делитель
    • 5.5 Факториал
    • 5.6 Quines in dc
    • 5.7 Печать всех простых чисел
    • 5.8 Целочисленная факторизация
    • 5.9 Обмен ключами Диффи – Хеллмана
  • 6 См. Также
  • 7 Ссылки
  • 8 Внешние ссылки
История

dc - самый старый из сохранившихся языков Unix. Когда ее домашний Bell Labs получил PDP-11, dc - написанный на B - был первым языком, работающим на новом компьютере, даже до появления ассемблера.. Кен Томпсон высказал мнение, что dc была самой первой программой, написанной на машине.

Основные операции

Чтобы умножить четыре и пять в постоянном токе (обратите внимание, что большая часть пробел не является обязательным):

$ cat << EOF>cal.txt 4 5 * p EOF $ dc cal.txt 20 $

Вы также можете получить результат с помощью команд:

$ echo "4 5 * p" | dc

или

$ dc - 4 5 * pq 20 $ dc 4 5 * p 20 q $ dc -e '4 5 * p'

Это переводится как «поместить четыре и пять в стек, затем с помощью оператора умножения извлеките два элемента из стека, умножьте их и поместите результат обратно в стек ». Затем используется команда pдля проверки (вывода на экран) верхнего элемента в стеке. Команда qзакрывает вызванный экземпляр dc. Обратите внимание, что числа должны располагаться на расстоянии друг от друга, даже если этого не требуется для некоторых операторов.

Арифметическая точность изменяется с помощью команды k, которая устанавливает количество цифр дробной части (количество цифр после точки ) для арифметических операций. Поскольку точность по умолчанию равна нулю, эта последовательность команд дает в результате 0:

2 3 / p

Путем настройки точности с помощью k, может быть произведено произвольное количество десятичных знаков. Эта последовательность команд выводит .66666.

5 k 2 3 / p

Чтобы оценить (12 + (- 3) 4) 11-22 {\ displaystyle {\ sqrt {\ left (12+ \ left (-3 \ right) ^ {4} \ right) \ over 11}} - 22}{\ displaystyle {\ sqrt {\ left (12+ \ left (-3 \ right) ^ {4} \ right) \ более 11}} - 22} : (vвычисляет квадратный корень из верхней части stack, а _используется для ввода отрицательного числа):

12 _3 4 ^ + 11 / v 22 - p

Чтобы поменять местами два верхних элемента стека используйте команду r. Чтобы продублировать верхний элемент, используйте команду d.

Ввод / вывод

Чтобы прочитать строку из stdin, используйте команду ?. Это будет оценивать строку, как если бы это была команда dc, поэтому необходимо, чтобы она была синтаксически правильной и потенциально представляла проблему безопасности, поскольку команда !dc допускает выполнение произвольной команды.

Как упоминалось выше, pбудет печатать верхнюю часть стека с новой строкой после нее. nвытянет верхнюю часть стека и выведет ее без завершающей новой строки. fсбросит весь стек с одной записью в строке.

dc также поддерживает произвольный ввод и вывод счисления. Команда iподнимет верхнюю часть стека и использует ее в качестве базы ввода. Шестнадцатеричные цифры должны быть в верхнем регистре, чтобы избежать конфликтов с командами постоянного тока, и ограничены A-F. Команда oделает то же самое для выходной базы, но имейте в виду, что входная база впоследствии повлияет на синтаксический анализ каждого числового значения, поэтому обычно рекомендуется сначала установить выходную базу. Поэтому 10oустанавливает систему счисления вывода на текущую систему счисления ввода, но обычно не на 10 (десять). Тем не менее Aoсбрасывает базу вывода на 10 (десять), независимо от базы ввода. Чтобы прочитать значения, команды K, Iи Oпоместят текущую точность, входную систему счисления и выходную систему счисления в верхнюю часть стека.

В качестве примера для преобразования из шестнадцатеричного в двоичное:

$ echo 16i2o DEADBEEFp | dc 11011110101011011011111011101111
Возможности языка

Регистры

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

Механизм, лежащий в основе макросов и условных операторов, - это регистр, который в dc является местом хранения с однозначным именем, которое может быть сохранено и получено из: scвыталкивает вершину стека и сохраняет его в регистре c, а lcпомещает значение регистра c в стек. Например:

3 sc 4 ​​lc * p

Регистры также могут рассматриваться как вторичные стеки, поэтому значения можно перемещать и выталкивать между ними и основным стеком с помощью Sи Lкоманды.

Строки

Строковые значения заключаются в символы [и ]и могут быть помещены в стек и сохранены в регистрах. Команда aпреобразует младший байт числового значения в символ ASCII, или, если верхняя часть стека является строкой, она заменит ее первым символом строка. Невозможно создать строки или выполнить манипуляции со строкой, кроме выполнения их с помощью команды xили печати с помощью команды P.

Символ #начинает комментарий до конца строки.

Макросы

Макросы затем реализуются, позволяя регистрам и записям стека быть строками, а также числами. Строку можно напечатать, но ее также можно выполнить (то есть обработать как последовательность команд постоянного тока). Так, например, мы можем сохранить макрос, чтобы добавить единицу, а затем умножить на 2 в регистре m:

[1 + 2 *] sm

, а затем (используя x, которая выполняет верхнюю часть стека), мы можем использовать ее так:

3 lm xp

Conditionals

Наконец, мы можем использовать этот макро-механизм для предоставления условных выражений. Команда = rизвлечет два значения из стека и выполнит макрос, хранящийся в регистре r, только если они равны. Таким образом, это напечатает строку равную, только если верх стека равен 5:

[[equal] p] sm 5 = m

Другие условные выражения >, !>, <, !<, !=, который выполнит указанный макрос, если два верхних значения в стеке больше, меньше или равны ("не больше"), меньше, больше или равны ("не меньше") и не равно соответственно.

Циклы

Циклы тогда возможны путем определения макроса, который (условно) повторно запускается. Простой факториал вершины стека может быть реализован как:

# F (x): return x! # если x-1>1 # return 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, который условно вызывает себя, выполняя каждый раз сложение, пока в стеке не останется только одно значение.

файл cat | dc -e "0d [? + 2z>a] salaxp"

Оператор ?считывает другую команду из входного потока. Если строка ввода содержит десятичное число, это значение добавляется в стек. Когда входной файл достигает конца файла, команда принимает значение NULL, и значение в стек не добавляется.

{эхо "5"; эхо «7»; } | dc -e "0d [? + 2z>a] salaxp"

И результат 12.

Строки ввода также могут быть сложными командами постоянного тока.

{echo "3 5 *"; эхо «4 3 *»; echo "5dd ++"} | dc -e "0d [? + 2z>a] salaxp"

И результат 42.

Обратите внимание, что, поскольку dc поддерживает произвольную точность, нет никаких проблем с числовым переполнением или потерей точности, нет независимо от того, сколько строк содержит входной поток, в отличие от аналогичного краткого решения в AWK.

Обратными сторонами этого решения являются: цикл прекращается при обнаружении пустой строки во входном потоке (технически, любая строка ввода, которая не добавить в стек хотя бы одно числовое значение); и, для обработки отрицательных чисел, начальные экземпляры '-' для обозначения отрицательного знака должны быть изменены на '_' во входном потоке из-за нестандартного отрицательного знака dc. Оператор ?в 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 

Факториал

Вычисление факториала входного значения, n! Знак равно ∏ я знак равно 1 ni {\ displaystyle n! = \ Prod _ {i = 1} ^ {n} i}п! = \ прод _ {я = 1} ^ {n} я

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

Quines in 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^][email#160;protected] [p]s[ddvs^3s!l#x0<2+l.x]ds.x' | dc

Эта программа была написана Мишелем Шарпантье. Он выводит последовательность простых чисел. Обратите внимание, что его можно сократить на один символ, что кажется минимальным решением.

echo '2p3p [dl! D2 + s!% 0 = @ l! L ^! <#]s#[0*ds^][email#160;protected] [p]s[ddvs^3s!l#x0<2+l.x]ds.x' | dc

Целочисленное разложение

dc -e' [n =] P? [P] s2 [lip / dli% 0 = 1dvsr] s12sid2% 0 = 13sidvsr [dli% 0 = 1lrli2 + dsi!>.] Ds.xd1 <2'

Эта программа также была написана Мишелем Шарпантье.

Существует более короткий

dc - e "[n =] P? [lfp / dlf% 0 = Fdvsr] sF [dsf] sJdvsr2sf [dlf% 0 = Flfdd2% + 1 + sflr 

и более быстрое решение (попробуйте с 200-битным числом 2- 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] + sflr dsMx [p] sMd1 

Обмен ключами Диффи-Хеллмана

Более сложный пример использования постоянного тока, встроенный в сценарий Perl, выполняет обмен ключами Диффи-Хеллмана. Это было популярно как блок подписи среди шифровальщиков во время дебатов по ITAR, где Короткий скрипт может быть запущен только с Perl и dc, вездесущими программами в Unix-подобных операционных системах:

#! / usr / bin / perl - -export-a-crypto-system-sig Diffie-Hellman-2 -строчки ($ g, $ e, $ m) = @ARGV, $ m || die "$ 0 gen exp mod \ n"; print ʻecho "16dio1 [d2% Sa2 / d0 

Прокомментированная версия немного проще для понимания и показывает, как использовать циклы, условные выражения и команду qдля возврата из макроса. С GNU версии dc можно использовать команду |для модульного возведения в степень произвольной точности без необходимости писать функцию X.

#! / usr / bin / perl my ($ 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, если e == 0 (в противном случае st ack: e) d 2% Sa # Сохранить e% 2 в a (stack: e) 2 / # compute e / 2 lXx # call X (e / 2) d * # compute X (e / 2) ^ 2 La1 = z # умножить на g, если e% 2 == 1 lm% # compute (g ^ e)% m] SX le # Загрузить e из регистра lXx # compute g ^ e% mp # Распечатать результат '';
См. Также
Ссылки
Внешние ссылки
Последняя правка сделана 2021-05-17 04:24:41
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте