Dc (UNIX)

dc(desk calculator)は、任意精度の演算をサポートするクロスプラットフォームな逆ポーランド記法の計算機ユーティリティです。ベル研究所のロバート・モリスによって開発され、UNIXユーティリティの中でも非常に古い歴史を持ちます。C言語の発明以前から存在し、その簡潔な構文が特徴です。伝統的に、中間記法計算機ユーティリティであるbcは、dcをバックエンドプロセスとして利用していました。

歴史



dcは現存するUnix言語の中で最も古いものです。ベル研究所PDP-11が導入された際、アセンブラよりも先に、B言語で記述されたdcが最初に動作した言語となりました。ケン・トンプソンはdcがこのマシンで書かれた最初のプログラムだと述べています。

基本的な演算



dcで4×5を計算するには、以下のように記述します。


4 5


この操作は、「4と5をスタックにプッシュし、乗算演算子()がスタックから2つの要素をポップし、それらを乗算した結果をスタックにプッシュする」という流れになります。

`p`コマンドはスタックの先頭要素を表示し、`q`コマンドはdcプログラムを終了します。演算子と数値の間のスペースは省略可能ですが、数値同士のスペースは省略できません。数値は、3.14や.318のような小数も使用できますが、指数表記(1.23e4など)には対応していません。

演算の精度(小数点以下の桁数)を変更するには`k`コマンドを使用します。デフォルト値は0なので、`2 3 / p`の結果は0となります。`5 k`のように精度を設定することで、任意の小数点以下の桁数で演算が可能です。


5 k
2 3 / p


上記のコマンドの結果は、.66666となります。

`v`コマンドはスタックの先頭要素の平方根を演算し、`_`は負の値を表します。例として、以下の計算を行うコマンドを示します。


12 _3 4 ^ + 11 / v 22 - p


これは、√((12+(-3)⁴)/11)-22 を計算します。

他にも、スタックの先頭2つの要素の順序を入れ替える`r`コマンドや、スタックの先頭要素を複製する`d`コマンドがあります。

入出力



`?`コマンドを利用すると、標準入力を1行読み込み、dcコマンドとして評価します。入力はdcコマンドとして正しい構文である必要があります。また、`!`コマンドを使用すると任意のユーザーコマンドを実行できるため、セキュリティ上の問題が発生する可能性があります。

`p`コマンドはスタックの先頭要素を表示して改行します。`n`コマンドはスタックからポップした値を改行なしで表示します。`f`コマンドはスタックの内容を先頭から順にすべて表示します。

dcでは、入力と出力の基数を任意に設定できます。`i`コマンドは入力時の基数を設定し、`o`コマンドは出力時の基数を設定します。利用できる基数は2から16までで、10以上の場合はAからFの大文字を使用します。現在の精度・入力基数・出力基数を得るには、`K`、`I`、`O`コマンドを使用します。これらのコマンドは現在の値をスタックにプッシュします。

以下は16進数を2進数に変換する例です。

言語の特徴的な機能



dcは、基本的な演算やスタック操作に加えて、マクロ、条件分岐、演算結果の一時保存などの機能を備えています。

レジスタ



dcのレジスタは、マクロや条件式の基本となる仕組みです。各レジスタは1文字の名前を持ちます。`sc`コマンドはスタックからポップした値をレジスタ`c`に保存し、`lc`コマンドはレジスタ`c`の値をスタックにプッシュします。


3 sc 4 lc p


上記の例では、レジスタを利用して3と4を掛けた結果を表示します。レジスタをスタックとして利用することもでき、`S`と`L`コマンドでプッシュとポップが可能です。

文字列



dcでは、`[`と`]`で囲まれたものを文字列として扱います。文字列は数値と同様にスタックにプッシュしたり、レジスタに格納したりできます。`a`コマンドはスタックから要素をポップし、数値の場合はASCII文字に変換してプッシュし、文字列の場合は最初の1文字をプッシュします。`x`コマンドでマクロとして実行したり、`P`コマンドで表示したりできますが、文字列を構築したり操作する方法はありません。

また、`#`から行末までをコメントとして扱うことができます。

マクロ



dcでは、レジスタやスタックに数値を格納するだけでなく、文字列を格納することでマクロ機能を実現しています。文字列は表示するだけでなく、dcコマンドとして実行できます。


[1 + 2 ] sm


上記の例では、1を加算して2を掛けるマクロをレジスタ`m`に格納しています。`x`コマンドでマクロを実行します。


3 lm x p


条件分岐



マクロの仕組みを利用して条件分岐を行うことができます。`=r`コマンドはスタックから要素を2つポップし、それらが等しい場合にレジスタ`r`に格納されたマクロを実行します。


[[Equal]p]sm 5 =m


上記の例では、スタックの先頭が5の場合に「Equal」と表示します。他にも、`>`、`!>`、`<`、`!<`、`!=`などの比較演算子があります。

ループ



dcで直接ループを記述することはできませんが、マクロを再帰的に実行することで実現できます。


[d1-d1

上記の例では、スタックの先頭の要素の階乗を計算します。

`1Q`コマンドはマクロから脱出し、`q`コマンドはマクロとその呼び出し元から脱出します。`z`コマンドはスタックの深さをプッシュします。



スタック全体の合計


レジスタ`a`に格納されたマクロを再帰的に呼び出して、スタック全体の合計を計算する例です。


1 2 4 8 16 100 # 加算したい数をスタックに積む
0d[+z1

結果は131となります。

ファイル中のdcコマンドの合計


ファイルの各行に記述されたdcコマンドを実行し、その合計値を計算する例です。各行に数値を記述することで、数値の合計を計算できます。


?d[+z1

dcの演算は無限精度であるため、オーバーフローや精度落ちを気にする必要がありません。ただし、空行に遭遇するとループが停止する点や、負符号を`_`に置換する必要がある点に注意が必要です。

単位変換


メートルで表された距離をフィートとインチに変換する例です。

最大公約数


ユークリッドの互除法を利用して最大公約数を求める例です。

階乗


入力された値nの階乗n!を計算する例です。

Quine


dcにもquineが存在します。

すべての素数を求める


すべての素数を表示する例です。

素因数分解


与えられた数の素因数分解を行う例です。

Diffie–Hellman鍵交換


Perlスクリプトに組み込まれたDiffie-Hellman鍵交換の例です。これは、ITAR議論の際にサイファーパンクたちの間で人気がありました。

dcは、その簡潔な構文と多様な機能により、Unix環境で長きにわたり利用されてきた計算機ユーティリティです。

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。