Dc (程序)

dc（desk calculator：桌面计算器）是采用逆波兰表示法的跨平台计算器，它支持任意精度算术。它是Robert Morris（英语：Robert Morris (cryptographer)）在贝尔实验室期间书写的，作为最老的Unix实用工具，先于C语言的发明。像那个年代的其他实用工具一样，它有着一组强力的特征和简洁的语法。传统上，采用中缀表示法的bc计算器程序是在dc之上实现的。 dc是幸存的最老的Unix语言。在贝尔实验室收到第一台PDP-11的时候，用B语言写成的dc是在这个新机器上运行的第一个语言，甚至在汇编器之前。 在dc中要做4和5的乘法： $ dc 4 5 * p 20 q 这可转译为“把4和5压入栈顶，通过乘法算符，从栈中弹出两个元素，将二者相乘并把结果压回栈顶”。接着使用p命令打印栈顶的元素。使用q命令退出此次调用的dc实例。注意数值相互间必须以空白分隔，但某些算符可以不必如此。 还可以用如下命令得到这个结果： $ dc -e '4 5 * p' 20 $ echo "4 5 * p" |dc 20 $ dc - 4 5*pq 20 $ cat <<EOF > cal.txt 4 5 * p EOF $ dc cal.txt 20 使用命令k来变更算术精度，它设置算术运算的小数位数。因为缺省精度是0，例如： $ dc -e "2 3 / p" 0 通过使用命令k调整精度，可以产生任意数目的小数数位，例如： $ dc -e "5 k 2 3 / p" .66666 dc有科学计算器的基本运算功能，比如求 12 + ( − 3 ) 4 11 − 22 {\textstyle {\begin{smallmatrix}{\sqrt {12+(-3)^{4} \over 11}}-22\end{smallmatrix}}} 的值： $ dc -e "2k 12 _3 4 ^ + 11 / v 22 - p" -19.10 其中，_用于输入负数，^计算幂，v计算平方根。 使用d命令复制栈顶元素。使用r命令对栈顶和仅次栈顶的两个元素进行对换。使用z命令压入当前栈深度，即执行z命令前栈中元素的数目。 使用?命令，从stdin读取一行并执行它。这允许从宏中向用户要求输入，故而此输入必须是语法上正确的，并且这有潜在的安全问题，因为dc的!命令可以执行任意系统命令。 前面提及过，p命令打印栈顶元素，带有随后的一个换行。n命令弹出栈顶元素并输出它，没有尾随换行。f命令打印整个栈，一项一行。 dc还支持控制输入和输出的基数。i命令弹出栈顶元素并将它用作输入基数。十六进制数字必须大写以避免和dc命令冲突，输入基数必须在2和16之间，输出基数必须大于等于2。o命令设置输出基数，要记住输入基数将影响对后面的所有数值的分析，所以通常建议先设置输出基数。例如将二进制转换成十六进制： $ echo 16o2i 11011110101011011011111011101111p | dc DEADBEEF 要读取设置的这些数值，K、I和O命令将压入当前精度、输入基数和输出基数到栈顶。 除了上述的基本算术和栈操作，dc包括了对宏、条件和存储结果用于以后检索的支持。 寄存器在dc中是有着单一字符名字的存贮位置，它可以通过命令来存储和检索，它是宏和条件的底层机制：sc弹出栈顶元素并将它存储入寄存器c，而lc将寄存器c的值压入栈顶。例如： 3 sc 4 lc * p 寄存器还被当作次要栈，可以使用S和L命令在它们和主要栈之间压入和弹出数值。存储栈顶元素到寄存器中并把这个元素留在栈顶，需要联合使用ds命令。 字符串是包围在[和]之中的字符，可以被压入栈顶和存入寄存器。使用x命令从栈顶弹出字符串并执行它，使用P命令从栈顶弹出并打印字符串，无尾随换行。a命令可以把数值的低位字节转换成ASCII字符，或者在栈顶是字符串时把它替换为这个字符串的第一个字符。此外没有方法去建造字符串或进行字符串操纵。 #字符开始一个注释直到此行结束。 通过允许寄存器和栈项目像数值一样存储字符串，从而实现了宏。一个字符串可以被打印，也可以被执行，就是说作为dc命令的序列而传递。例如可以把一个宏“加1并接着乘以2”存储到一个寄存器m中： [1 + 2 *] sm 通过使用x命令弹出栈顶的字符串并执行之，如下这样使用存储的宏： 3 lm x p Q命令从栈顶弹出一个值作为退出宏的层数，比如2Q命令退出2层宏，它永不导致退出dc。q命令退出2层宏，如果宏少于2层则退出dc。 最后提供了有条件执行宏的机制。命令=r将从栈顶弹出两个值，如果二者相等，则执行存储在寄存器r中的宏。如下命令序列将在原栈顶元素等于5的条件下打印字符串equal。 [[equal]p] sm d 5 =m 这里使用了d命令保留原栈顶元素。其他条件有>、!>、<、!<、!=，如果栈顶元素分别大于、不大于（小于等于）、小于、不小于（大于等于）、不等于仅次于栈顶的元素，则执行指定宏。 通过定义有条件的调用自身的递归宏，迭代也是可行的。一个简单的对栈顶元素的阶乘过程： # F(x): return x! # if x-1 > 1 # return x * F(x-1) # otherwise # return x 可实现为： [d1-d1<F*]dsFxp 这里宏中的第一个d命令相当于分配了一个局部变量。 Unix V7手册页举出的编程实例为打印阶乘n!的前10个值： $ dc -e "[la1+dsa*pla10>y]sy 0sa1 lyx" 1 2 6 24 120 720 5040 40320 362880 3628800 这个程序实现了For循环，将作为循环体的宏[la1+dsa*pla10>y]存储在寄存器y中；把寄存器a作为循环计数器，设其初始值为0，将0!的值1压入栈顶；从寄存器y中取出宏并执行之。宏中的la1+dsa将计数器a的数值加1，并将这个值留在栈顶；随后*p从栈中弹出两个元素进行乘法并把结果压入栈中，打印这个结果；随后la10>y将计数器a的数值和数值10压入栈中，判断位于栈顶的10是否大于计数器的数值，即计数器的数值是否小于10，弹出二者并在判断成立的条件下再次执行存储在寄存器y中的宏。计数器a的数值从0增加到10，宏一共被执行了10次。 bc 计算器输入方法（英语：Calculator input methods） 堆栈机器 dc(1): an arbitrary precision calculator – Linux用户命令（User Commands）手册页 Brian Kernighan and Ken Thompson. A nerdy delight for any Vintage Computer Fest 2019 attendee: Kernighan interviewing Thompson about Unix. YouTube. 事件发生在 29m45s. [September 3, 2019]. （原始内容存档于2022-02-01）.  The sources for the manual page for 7th Edition Unix dc. [2020-09-25]. （原始内容存档于2019-09-24）.  Ritchie, Dennis M. The Evolution of the Unix Timesharing System. Sep 1979 [2019-05-31]. （原始内容存档于2010-05-06）.  McIlroy, M. D. A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (技术报告). CSTR. Bell Labs. 1987 [2019-05-31]. 139. （原始内容存档 (PDF)于2019-11-30）.  软件包dc（页面存档备份，存于互联网档案馆）在Debian GNU/Linux仓库中 bc的原生Windows移植包括了dc 嵌入到网页中的dc（页面存档备份，存于互联网档案馆） The unix dc(1) command, this is the esoteric language that "made it big". （页面存档备份，存于互联网档案馆）