dc Programming
はじめに
dcについて
dc は、arbitrary precision desk calculator であり、reverse Polish notation (RPN) を採用しているのが特徴である。今は使われていないかもしれないが、UNIX で配布されている。また、
bc というのもあるが、これは、C language like syntaxを特徴とし、かつては、dc用のprogram filesをoutputできたらしいが、GNU BC では、独立したプログラムとなっており、残念ながら、できない。
dcとForth
同じ RPN を採用しており、スタックが重要であることは共通しているが、やはり、微妙に異なる。dc の manual を見ないと書けない。
dc
導入
終了 q C-c
起動 command-line options
-e 'expr'
--expression='expr'
'expr' as dc [[commands]]
-f 'file'
--file='file'
read and evaluate dc commands from 'file'
オプションの後に、パラメーターが残っている場合は追加fileとして解釈され、その内容が評価される。特に '-' というファイル名は standard input stream を指す。
数とarbitrary precision
decimal point 以下の数字の数(precision value)は default で 0、すなわち整数である。例えば、小数点以下20桁まで表示するとすれば、20k と入力する。負の数は'_'を使う。'-' は substraction という binary operation である。また、実数は小数形式であり、exponential notation はない。
commands
'p' print TOS with a newline. TOS remains. (TOS=top of stack)
'n' print TOS without a newline. TOS is popped off. (GNU extension)
'P' print TOS without a newline. TOS is popped off.
if a string, print it.
if numbers <= 256 print the ASCII character
if numbers > 256 print the value of the number modulo 256
'f' print the entire contents of the stack without altering anything.
arithmetic
+ - * / % ^
'~' quotient & remainder
'|' pops three values and computes the modular exponentiation.
reduction modulus, exponent, base(GNU extension)
'v' square root
stack control
'c' clear stack
'd' duplicate
'r' swap the top two values on the stack. (GNU extension)
registers
'sr' store TOS into register r, popped TOS off.
'lr' push the value of register r, without popping off.
'Sr' push TOS into register r as TOS of register r.
'Lr' push TOS of register r onto the main stack.
parameters
'i' input radix
'o' output radix
input radix must be between 2 and 16 inclusive.
outp radix must be at least 2. hexadecimalのとき、A through Fも使う。
注意)input radixをhexadecimalにして、再度、decimalに戻すときは、Aiと入力する。
1000 o
123456789 p => 123 456 789
100000 o
123456789 p => 01234 56789
strings
dcはstringsについては、printするか、macroとして実行する。
registersでもstackでもstringsを保存できる。
[characters] eg) '[foo]P' prints 'foo' with no newline
'a' asciify eg)42ap=>* 13ap=>Carridge Return
'x' pop the value off the stack and execute as a macro .
if it is a number, simply pushing back onto the stack.
'>r' pops two values off the stack and compares them,
if TOS is greater, execute the contents of register r.
eg) '1 2>a' => invoking register 'a''s contents
'!>r' not greater
'=r' if equal
'?' allows a macro to request input from the user
'q' exit
'Q' pops a value off the stack and uses it
as a count of levels of macro execution to b
status inquiry
'Z' number of digits (ignoring minus sign and decimal point)
or number of characters X number of fraction digits .for a string, 0.
'x' current stack depth: the nubmer of objects on the stack
before the execution of 'z' command.
miscellaneous
'!' run a system command
'#' the rest of the line as a comment (GNU extension)
':r' store in the array r eg)<value><index>:r
';r' push from the array r. eg)<index>;r =><value>
サンプルプログラム
dc のサンプルプログラムはインターネットで探してもほとんど見つからない。
Morris & Cherry のmanualより
# print the number 0-9
[lip1+ si li10a>]sa
0si lax
ibm aixのcommands referenceより
# factorial of n 最初の1行は1との大小で実行するマクロを切り替えていることに注意。
[d 1 >b d 1 <r] sf # if 1>n do b; if 1<n do r
[d 1 +] sb # return f(n)=n*f(n-1)
[d 1 - lf x *]sr # return f(n)=n*f(n-1)
10 lf x p => 3628800
5 lf x p => 120
注)comment である"#"はGNU extension
Plan 9 manual
# print the first ten values of n!
[la1+dsa*pla10>y]sy
0sa1 lyx
Ted Faber
# average calculation
0st0sn (t:total, n:number)
[lt+stln1+snz0<az0=d]sa
[ltln/p0st0sn]sd
$dc dc.avg -
5 k
1 2 3 4 5 6 7 8 9 10 lax
5.50000
Everything2.com
# FizzBuzz in dc
[sg []] sX
[
[Buzz] l5 0!=X
[Fizz] l3 0!=X
n p sG
] sA
[ln p sG] sB
[
ln 3 % s3
ln 5 % s5
l3 l5 * d 0=A 0 !=B
ln 1 + d sn
101 > C
] sC
1 sn
lCx
# shorter version
[sg[]]sx1[ddd3%d[Fizz]r0!=xnr5%d[Buzz]r0!=xn*0=xpsg1+dd101>M]dsMx
(注)FizzBuzzとは
one two three ... と続け、ある数の倍数をfizz, buzzに替える。
両方の倍数ならfizzbuzzとする。
MKS Toolkit9.1 Documentation Build7から
# print out the first 12 elements of the Fibonacci sequence
1 sa
1 sb
2 sc
[la lb + p lb sa sb lc 1 + d sc 13 >z] sz
[lr*lr1-dsr0<a]sa
10sr1 lla p sx lp p sx lz x
wikipedia
(1) print the string 'equal' only if TOS=5
[1+2*] sm
3 lm x p
[[equal]p] sm 5 =m
(2) convert from meters to feet and inches
dc -e '[[Enter a number (meters), or 0 to exit]psj]sh[q]sz \
[lhx?d0=z10k39.37009*.5+0k12~1/rn[feet]Pn[inches]P10Pdx]dx' (実際は1行)
(3) Euclidean algorithm for search GCD
dc -e '??[dSarLa%d0<a]dsaxp' # shortest
dc -e '[a=]P?[b=]P?[dSarLa%d0<a]dsax+[GCD:]Pp' # more comfortable version
私が考えたプログラム例
factorial
10!
(1) 10sr1[lr*lr1-dsr0<a]dsaxp # two registers
(1)' [lr*lr1-dsr0<a]sa
10sr1 laxp
(2) 1 10[dsr*lr1-d0<a]dsax+p # two registers (注)tosが0となるので、+でしめる。
(3) 1 10[dSa*La1-d0<a]dsax+p # one register
(1/2)の階乗の計算
(1) (1/2)^1~(1/2)^17
20 k
[2/dli1+dsi:ali17>a]sa
0sil lax
# 計算結果は配列に収納
(2) n=1 0.5000の形で表示
[li1+d[= ]Pn[]Pdsi;an10anli17>b]sb
# '10a'=newline n10anの代わりにpを用いると、stackにデータが残る。
0si lbx
最終更新:2010年09月06日 21:50