(Translated by https://www.hiragana.jp/)
dc (UNIX) - Wikipedia コンテンツにスキップ

dc (UNIX)

出典しゅってん: フリー百科ひゃっか事典じてん『ウィキペディア(Wikipedia)』
dc
作者さくしゃ ロバート・H・モリス
(ベル研究所けんきゅうじょ)
プログラミング
言語げんご
B言語げんご
対応たいおうOS UNIX, Unixけい, Plan 9
プラットフォーム クロスプラットフォーム
種別しゅべつ コマンド
ライセンス GPL 3.0
テンプレートを表示ひょうじ

dc (desk calculator; 卓上たくじょう計算けいさん) は、任意にんい精度せいど演算えんざんをサポートする、クロスプラットフォームぎゃくポーランド記法きほう計算けいさんユーティリティである[1]ロバート・モリスベル研究所けんきゅうじょにいるあいだ開発かいはつされたこのソフトウェアは、もっとふるUnix ユーティリティのひとつで[2]、これは C 言語げんご発明はつめいよりもまえのことである。どう世代せだいほかのユーティリティのように一連いちれん強力きょうりょく機能きのうっているが、その構文こうぶん簡潔かんけつである[3][4]伝統でんとうてきに、中間ちゅうかん記法きほう計算けいさんユーティリティである bc は dc をバックエンドプロセスとして利用りようしていた。

ここでは、言語げんご一般いっぱんてき傾向けいこうしめすためにいくつかのれい紹介しょうかいしている。完全かんぜんなコマンドと構文こうぶんについては、それぞれの実装じっそうによる man ページ参照さんしょうされたい。

歴史れきし

[編集へんしゅう]

dc は現存げんそんする Unix 言語げんごなかもっとふるいものである。ベル研究所けんきゅうじょPDP-11導入どうにゅうされたときには、アセンブラよりもさきに、(B 言語げんごかれた) dc がそのマシンでうご最初さいしょ言語げんごなった[5]ケン・トンプソンは、dc がこのマシンでかれた最初さいしょのプログラムだとも発言はつげんしている[2]

基本きほんてき演算えんざん

[編集へんしゅう]

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'

これらの動作どうさは「4 と 5 をスタックにプッシュし、乗算じょうざん演算えんざん (*) によってスタックから要素ようそを 2 つポップし、それらをかけわせたをスタックにプッシュする」ものである。p コマンドはスタックの先頭せんとう要素ようそ表示ひょうじする。q コマンドは dc プログラムを終了しゅうりょうする。演算えんざん同士どうし演算えんざん数字すうじあいだのスペースは省略しょうりゃくできるが、数字すうじ同士どうしあいだのスペースは省略しょうりゃくできないことに注意ちゅういする。また、数値すうち3.14.318 などの小数しょうすうであってもよいが、指数しすう表記ひょうき (1.23e4 のような表記ひょうき) には対応たいおうしていない。

演算えんざん精度せいど (演算えんざん有効ゆうこうとする小数点しょうすうてん以下いか桁数けたすう) を変更へんこうするには k コマンドを利用りようする。起動きどうのデフォルトは 0 であるので、つぎの dc コマンドの結果けっか0 となる:

2 3 / p

k コマンドを利用りようして適当てきとう精度せいど設定せっていすることで、任意にんい小数点しょうすうてん以下いかけた演算えんざんできる。つぎの dc コマンドの結果けっか.66666 となる:

5 k
2 3 / p

つぎの dc コマンドは 計算けいさんする (v コマンドはスタックの先頭せんとう平方根へいほうこん演算えんざんし、_まけ符号ふごうである):

12 _3 4 ^ + 11 / v 22 - p

そのにも、スタックの先頭せんとう 2 つの要素ようそじゅんえる r コマンドやスタックの先頭せんとう要素ようそ複製ふくせいする d コマンドなどがある。

入出力にゅうしゅつりょく

[編集へんしゅう]

? コマンドを利用りようして標準ひょうじゅん入力にゅうりょくを 1 ぎょうむことができる。このコマンドは入力にゅうりょくされたくだりを dc コマンドとして評価ひょうかする。そのため、入力にゅうりょくは dc コマンドとしてただしい構文こうぶんである必要ひつようがあるほか、! コマンドを利用りようして任意にんいのユーザコマンドを実行じっこうできるため、セキュリティじょう問題もんだい発生はっせいするおそれすらある。

前述ぜんじゅつしたとおり、p コマンドはスタックの先頭せんとう要素ようそ表示ひょうじして改行かいぎょうする。n コマンドはスタックからポップした改行かいぎょうともなわずに表示ひょうじする。f コマンドはスタックの内容ないよう先頭せんとうからじゅんにすべて表示ひょうじする。

dc はまた、入力にゅうりょく出力しゅつりょく利用りようする基数きすう任意にんい設定せっていできる。i コマンドは入力にゅうりょく基数きすうとしてスタックをポップした設定せっていする。dc コマンドとの衝突しょうとつけるため、利用りようできる基数きすうは 2 から 16 にかぎられ、基数きすうに 10 以上いじょう指定していする場合ばあいは A から F の大文字おおもじかずとして利用りようする (小文字こもじ利用りようできない)。同様どうようo コマンドは出力しゅつりょく基数きすうとしてスタックからポップした設定せっていする。また、現在げんざい精度せいど入力にゅうりょく基数きすう出力しゅつりょく基数きすうるためには、KIO コマンドを利用りようする。これらは現在げんざいをスタックにプッシュする。

以下いかしめすのは 16 進数しんすう入力にゅうりょくを 2 進数しんすう変換へんかんするれいである:

$ echo 16i2o DEADBEEF p | dc
11011110101011011011111011101111

言語げんご特徴とくちょうてき機能きのう

[編集へんしゅう]

dc は、うえべた基本きほんてき演算えんざんやスタック操作そうさくわえて、マクロ条件じょうけん分岐ぶんき演算えんざん結果けっか一時いちじ保存ほぞんなどの機能きのうそなえている。

レジスタ

[編集へんしゅう]

dc におけるレジスタは、マクロや条件じょうけんしき基本きほんとなる仕組しくみである。それぞれのレジスタは 1 文字もじ名前なまえっている。レジスタを利用りようして保存ほぞんしたりスタックにしたりすることができる。sc コマンドはスタックからポップした要素ようそをレジスタ c保存ほぞんする。lc コマンドは c レジスタのをスタックにプッシュする。以下いかしめすのはレジスタを利用りようするれいである:

3 sc 4 lc * p

レジスタをスタックとして利用りようすることもできる。メインのスタックとレジスタのスタックとのあいだでプッシュ・ポップするには SL コマンドを利用りようする。

文字もじれつ

[編集へんしゅう]

dc では []かこまれたものを文字もじれつとしてあつかう。文字もじれつ数値すうち同様どうようにスタックにプッシュしたりレジスタに格納かくのうしたりできる。a コマンドはスタックから要素ようそをポップし、それが数値すうちである場合ばあい下位かいバイトを ASCII 文字もじ変換へんかんしてプッシュし、文字もじれつ場合ばあい最初さいしょの 1 文字もじをプッシュする。文字もじれつx コマンドでマクロとして実行じっこうしたり P コマンドで表示ひょうじすることはできるが、文字もじれつ構築こうちくしたり文字もじれつ操作そうさおこな方法ほうほうはない。

また、dc では # から行末ゆくすえまでをコメントとしてあつかい、実行じっこうには影響えいきょうおよぼさない。

dc ではレジスタやスタックに数値すうちだけでなく、文字もじれつ格納かくのうできるようにすることでマクロ機能きのう実現じつげんしている。文字もじれつ表示ひょうじするだけでなく、それ自身じしんを dc コマンドとして実行じっこうすることもできる。以下いかしめすのは 1 を加算かさんして 2 をけるマクロをレジスタ m に格納かくのうするれいである:

[1 + 2 *] sm

そしてつぎのようにマクロをす (x コマンドはスタックからポップしたをマクロとして実行じっこうする):

3 lm x p

条件じょうけん分岐ぶんき

[編集へんしゅう]

マクロの仕組しくみを利用りようして条件じょうけん分岐ぶんきおこなうことができる。=r コマンドはスタックから要素ようそを 2 つポップし、それらのひとしいときにレジスタ r格納かくのうされているマクロを実行じっこうする。以下いかしめすのはスタックの先頭せんとうに 5 があるときに Equal表示ひょうじするれいである:

[[Equal]p]sm 5 =m

そのにも、> (もともとの先頭せんとうおおきい場合ばあいにマクロ実行じっこう)、!> (おおきくない場合ばあい)、< (ちいさい場合ばあい)、!< (ちいさくない場合ばあい)、!= (ひとしくない場合ばあい) がある。

dc でループそのものをおこな方法ほうほうはないが、マクロを再帰さいきてき実行じっこうすることで再現さいげんできる。スタックの先頭せんとう要素ようそかいじょうもとめるにはつぎのようにする:

# F(x): return x!
# if x-1 > 1
#     return x * F(x-1)
# otherwise
#     return x
[d1-d1<F*]dsFxp

1Q コマンドはマクロから脱出だっしゅつする。これにたいして q コマンドはそのマクロとそのマクロをしたマクロから脱出だっしゅつする。マクロの深度しんどが 2 未満みまん場合ばあいは dc プログラムをも終了しゅうりょうする。z コマンドは現在げんざいの (z コマンドの実行じっこうまえの) スタックのふかさをプッシュする。

スタック全体ぜんたい合計ごうけい

[編集へんしゅう]

これはレジスタ a に格納かくのうされたマクロを再帰さいきてきしてスタック全体ぜんたい合計ごうけい計算けいさんする。マクロの動作どうさは、まずスタックの先頭せんとう 2 をわせ (+)、スタックのふかさが 1 よりおおきい場合ばあい再帰さいきする (1z<a) ものである。マクロぶん直前ちょくぜん0d一見いっけん必要ひつようないようにおもえるがが、加算かさん演算えんざんがスタックの先頭せんとう 2 の要素ようそ確実かくじつせることを保証ほしょうするために必要ひつようである。

1 2 4 8 16 100  # 加算かさんしたいかずをスタックにむ
0d[+z1<a]dsaxp  # すべて加算かさんして表示ひょうじ

実行じっこう結果けっか131 となる。

ファイルちゅうの dc コマンドの合計ごうけい

[編集へんしゅう]

ファイルの各行かくこう記述きじゅつされた dc コマンドを実行じっこうし、その合計ごうけい計算けいさんする。たんなる数値すうちは dc コマンドとして有効ゆうこうであるので、くだりごとに記述きじゅつされた数値すうち合計ごうけいることもできる。

これもうえれい同様どうようにレジスタ a に格納かくのうされたマクロを再帰さいきてきして合計ごうけい計算けいさんしている。

$ cat file | dc -e '0d[?+z1<a]dsaxp'

? コマンドは標準ひょうじゅん入力にゅうりょくから dc コマンドをみ、結果けっかをスタックにプッシュする。ファイルの終端しゅうたんたっした場合ばあいはコマンドはまれず、スタックにはなにもプッシュされない。

$ { echo "5"; echo "7"; } | dc -e '0d[?+z1<a]dsaxp'

この結果けっか12 となる。 入力にゅうりょくの dc コマンドは複雑ふくざつでもい。

$ { echo "3 5 *"; echo "4 3 *"; echo "5dd++"; } | dc -e '0d[?+z1<a]dsaxp'

この結果けっか より 42 となる。

この手法しゅほう利用りようすることの長所ちょうしょは、dc の演算えんざん無限むげん精度せいどであるので、 AWK などの簡明かんめい手法しゅほうもちいる場合ばあいこりうるオーバーフロー精度せいどちが発生はっせいしないことである。

たいして短所たんしょもあり、空行くうぎょう (技術ぎじゅつてきには要素ようそをプッシュしないくだり) に遭遇そうぐうするとループが停止ていしすること、まけ符号ふごう を dc の符号ふごう _置換ちかんする必要ひつようがあることがげられる。dc の ? には空行くうぎょうとファイル終端しゅうたん見分みわけるきれいな方法ほうほう提供ていきょうされていない。

単位たんい変換へんかん

[編集へんしゅう]

以下いかしめすのは、ワンライナーでかれた較的簡単かんたん単位たんい変換へんかんプログラムのれいである:

$ dc -e '[[Enter a number (metres), or 0 to exit]psj]sh[q]sz[lhx?d0=z10k39.370079*.5+0k12~1/rn[ feet ]Pn[ inches]P10Pdx]dx'

このれいはメートルであらわされた距離きょりをフィートとインチに変換へんかんする。ユーザに入力にゅうりょくうながし、適切てきせつ形式けいしき変換へんかん結果けっか出力しゅつりょくし、べつ数値すうち変換へんかんするためにループしている。

最大公約数さいだいこうやくすう

[編集へんしゅう]

以下いかしめすのは互除ほう利用りようして最大公約数さいだいこうやくすうもとめるれいである:

$ 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 にも quine存在そんざいする。

$ 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+l.x]ds.x' | dc

このプログラムは Michel Charpentier によってかれた、すべての素数そすう表示ひょうじするプログラムである。このプログラムはつぎのように短縮たんしゅくでき、おそらくこれが最短さいたんであるとおもわれる。

$ echo '2p3p[dl!d2+s!%0=@l!l^!<#]s#[0*ds^]s@[p]s&[ddvs^3s!l#x0<&2+l.x]ds.x' | dc

素因数そいんすう分解ぶんかい

[編集へんしゅう]

これもまた Michel Charpentier によってかれた[6]:

$ 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<Jd1<M]dsMx"

より高速こうそくなものでは (200 bit のかず ためすなら 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+sflr>N]dsMx[p]sMd1<M"

Diffie–Hellman かぎ交換こうかん

[編集へんしゅう]

より複雑ふくざつれいでは、Perl スクリプトにまれている Diffie–Hellman かぎ交換こうかんがある。これは ITAR 議論ぎろんのときにサイファーパンクたちのあいだ人気にんきであった。このスクリプトは Unix ライクな OS にはどこにでもある Perl と dc だけで実行じっこうできる[7]:

#!/usr/bin/perl -- -export-a-crypto-system-sig Diffie-Hellman-2-lines
($g, $e, $m) = @ARGV, $m || die "$0 gen exp mod\n";
print `echo "16dio1[d2%Sa2/d0<X+d*La1=z\U$m%0]SX$e"[$g*]\EszlXx+p | dc`

これのコメントきのバージョンはすこしわかりやすく、ループや条件じょうけん分岐ぶんき、マクロから脱出だっしゅつするための q コマンドなどの使つかかたしめされている。GNU の dc では、以下いかのコードちゅうでレジスタ X に格納かくのうされるマクロを使つかわりに | コマンドでべき剰余じょうよ演算えんざんできる。

#!/usr/bin/perl

my ($g, $e, $m) = map { "\U$_" } @ARGV;
die "$0 gen exp mod\n" unless $m;

print `echo $g $e $m | dc -e '
# Hex input and output
16dio
# Read m, e and g from stdin on one line
?SmSeSg

# Function z: return g * top of stack
[lg*]sz

# Function Q: remove the top of the stack and return 1
[sb1q]sQ

# Function X(e): recursively compute g^e % m
# It is the same as Sm^Lm%, but handles arbitrarily large exponents.
# Stack at entry: e
# Stack at exit: g^e % m
# Since e may be very large, this uses the property that 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 (otherwise, stack: e)
    d 2% Sa # Store e%2 in a (stack: e)
    2/      # compute e/2
    lXx     # call X(e/2)
    d*      # compute X(e/2)^2
    La1=z   # multiply by g if e%2==1
    lm %    # compute (g^e) % m
] SX

le          # Load e from the register
lXx         # compute g^e % m
p           # Print the result
'`;

関連かんれん項目こうもく

[編集へんしゅう]

脚注きゃくちゅう出典しゅってん

[編集へんしゅう]
  1. ^ dc(1): an arbitrary precision calculator – Linux User Commands Manual (en)
  2. ^ a b Brian Kernighan and Ken Thompson. A nerdy delight for any Vintage Computer Fest 2019 attendee: Kernighan interviewing Thompson about Unix. YouTube. 該当がいとう時間じかん: 29m45s. 2019ねん9がつ3にち閲覧えつらん
  3. ^ The sources for the manual page for 7th Edition Unix dc (Internet Archive)”. 2021ねん3がつ16にち閲覧えつらん
  4. ^ Ritchie, Dennis M. (Sep 1979). “The Evolution of the Unix Timesharing System”. 2010ねん5がつ6にち時点じてんオリジナルよりアーカイブ。2021ねん3がつ16にち閲覧えつらん
  5. ^ McIlroy, M. D. (1987). A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (Technical report). CSTR. Bell Labs. 139。
  6. ^ Advanced Bash-Scripting Guide, Chapter 16, Example 16-52 (Factorization)”. 2020ねん9がつ20日はつか閲覧えつらん
  7. ^ Adam Back. “Diffie–Hellman in 2 lines of Perl”. 5 Jan 2009閲覧えつらん

外部がいぶリンク

[編集へんしゅう]