dc（desk calculator：桌面計算器）是採用逆波蘭表示法的跨平臺計算器，它支援任意精度算術。它是在貝爾實驗室期間書寫的，作為最老的 Unix 實用工具，先於 C 語言的發明。像那個年代的其他實用工具一樣，它有著一組強力的特徵和簡潔的語法。傳統上，採用中綴表示法的 bc 計算器程式是在 dc 之上實現的。 歷史 dc 是倖存的最老的 Unix 語言。在貝爾實驗室收到第一臺 PDP11 的時候，用 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 5pq 20 cat EOF caltxt 4 5 p EOF dc caltxt 20 使用命令 k 來變更算術精度，它設定算術運算的小數位數。因為預設精度是 0，例如： dc e 10946 6765 p 1 透過使用命令 k 調整精度，可以產生任意數目的小數數位，例如： dc e 7k 10946 6765 p 16180339 dc 有科學計算器的基本運算功能，比如求黃金分割率 frac sqrt 5 1 2 的值： dc e 7k 5 v 1 2 p 16180339 dc 將輸入數值的前導_識別為負號，命令 計算冪，命令 v 計算平方根。 d 命令用於複製棧頂元素。r 命令用於對棧頂和僅次棧頂的兩個元素進行對換。z 命令用於壓入當前棧深度，即執行 z 命令前棧中元素的數目。 輸入 輸出 使用？命令，從 stdin 讀取一行並執行它。這允許從宏中向用戶要求輸入，故而此輸入必須是語法上正確的，並且這有潛在的安全問題，因為 dc 的！命令可以執行任意系統命令。 前面提及過，p 命令列印棧頂元素，帶有隨後的一個換行。n 命令彈出棧頂元素並輸出它，沒有尾隨換行。f 命令列印整個棧，從棧頂到棧底並且一項一行。 dc 還支援控制輸入和輸出的底數。o 命令設定輸出底數，輸出底數必須大於等於 2。i 命令彈出棧頂元素並將它用作輸入底數，輸入底數必須在 2 和 16 之間，十六進位制數字必須大寫以避免和 dc 命令衝突。要記住輸入底數將影響對後面的所有數值的分析，所以通常建議在設定輸入底數之前先設定輸出底數。例如將二進位制轉換成十六進位制： echo 16o2i 1001101010111100110111101111 p dc 9ABCDEF 要讀取設定的這些數值，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 lmx p Q 命令從棧頂彈出一個值作為退出宏的層數，比如 2Q 命令退出 2 層宏，它永不導致退出 dc。q 命令退出 2 層宏，如果宏少於 2 層則退出 dc。 條件 最後提供了有條件執行宏的機制。命令 r 將從棧頂彈出兩個值，如果二者相等，則執行儲存在暫存器 r 中的宏。如下命令序列將在原棧頂元素等於 5 的條件下列印字串 equal。 equal p sm d5m 這裡使用了 d 命令保留原棧頂元素。其他條件有 、、、、，如果棧頂元素分別大於、不大於（小於等於）、小於、不小於（大於等於）、不等於僅次於棧頂的元素，則執行指定的宏。注意不同於 Forth、PostScript 和 Factor，在不等式比較中的運算元的次序同在算術中的次序相反， 等價於中綴表示法的，然而在時執行暫存器的內容。下面是其執行示例： echo 5 dc e equal p sm d5m equal echo 5 dc e equal pq sm d5m not equal p x equal echo 4 dc e equal pq sm d5m not equal p x not equal 迭代示例 透過定義進行有條件的遞迴呼叫的宏，可以實行迭代運算。 階乘 下面是採用了互遞迴對棧頂元素計算階乘 n ncdot n1 的過程： F x x 1 G x x G x x F x1 它在 x 0 時有效，這裡的虛擬碼採用了條件運算子而非條件語句。它可實現為： d 1 lFx sG d1G dsFx 它可以進一步採用尾遞迴實現為： d 1 lFx sG d1G dsFx 1 z1H dsHx 這裡的運算由兩個步驟串接而成，首先將遞減的整數壓入堆疊形成整數集 mathbb Z 上偏序關係 ge 的區間 n 1，然後在這個數列上進行應用乘法運算的右歸約得出一個最終的結果值。這裡的命令 z，將當前的堆疊深度即堆疊中元素數目壓入棧頂。還可以進一步增加針對 x 0 情況的預處理。下面是其執行示例： echo 0 dc e d1 sad0a d 1 lFx sG d1G dsFx 1 z1H dsHx p 1 echo 9 dc e d1 sad0a d 1 lFx sG d1G dsFx 1 z1H dsHx p 362880 下面的例子採用迭代法打印出階乘 n prod_i 1n i 的前 n 項的數列： n x i 0 F x i i 1 x x i print x i n F x x F 1 這裡迭代的是需要初始化的堆疊中的值 x，它是 n，其初始值 1 是 0；i 既是迭代的遞增計數器，也是的運算元，其遞增形成整數集 mathbb Z 上偏序關係 le 的區間 1 n，同步地在這個數列上進行輸出中間值的應用乘法運算的左歸約得出結果數列。它可實現為： sn 0si 1 li1dsi p lilnF dsFx 下面是其執行示例： echo 6 dc e sn 0si 1 li1dsi p lilnF dsFx 1 2 6 24 120 720 可以將它改為計算單個的階乘： echo 0 dc e sn 0si 1 li1dsi lilnF dsFx p 1 echo 9 dc e sn 0si 1 li1dsi lilnF dsFx p 362880 斐波那契數 下面是採用了互遞迴的對棧頂元素計算斐波那契數的過程： F x x 1 G x x G x F x1 F x2 可實現為： d 2 lFx r 1 lFx sG d1G dsFx 這裡的 r 命令反轉（交換）棧頂兩個元素的次序。它可以進一步採用記憶化而寫為： F x x 1 M x x M x if x in a a x else temp G x a x temp temp G x F x1 F x2 基於陣列儲存命令：和訪問命令；，它可實現為： 0Sa 1si aq sN dliN lGx dli1dsia sM d 2 lFx r 1 lFx sG d1M dsFx Lasa 下面是其執行示例，展示了透過給它加列印斷點來觀察其遞迴呼叫的規模和詳細步驟： echo 0 dc e d 2 lFx r 1 lFx sG d1G dsFx p 0 echo 20 dc e d 2 lFx r 1 lFx sG d1G dsFx p 6765 echo 21 dc e d 2 lFx r 1 lFx sG d1G dsFx p 10946 echo 20 dc e p d 2 lFx r 1 lFx sG d1G dsFx wc l 10945 echo 20 dc e 0Sa 1si aq sN p dliN lGx dli1dsia sM d 2 lFx r 1 lFx sG d1M dsFx Lasa wc l 36 echo 6 dc e 0Sa 1si aq sN zn F np dliN lGx dli1dsia sM d 2 lFx r 1 lFx sG d1M dsFx Lasa 1 F6 2 F4 3 F2 3 F3 4 F2 2 F5 3 F3 3 F4 echo 6 dc e 0Sa 1si aq sN zn F np dliN lGx dli1dsia sM d 1 lFx r 2 lFx sG d1M dsFx Lasa 1 F6 2 F5 3 F4 4 F3 5 F2 4 F2 3 F3 2 F4 在遞迴定義 F_n F_n1 F_n2 的遞迴呼叫中，隨著 F_n 的索引 n 的遞減，而遞迴下降至被計算出來並儲存的第一項 F_2 F_1 F_0，然後沿著呼叫鏈逐級返回；在遞迴的每個步驟中都要計算並儲存 F_n，它所需要的 F_n1 和 F_n2 這兩項之中，如果首先進行 F_n2 遞迴呼叫並從其返回，則 F_n1 也需要計算並儲存，為此需要訪問已儲存的 F_n2 和 F_n3；如果首先進行 F_n1 遞迴呼叫並從其返回，則需要訪問已儲存的 F_n2；這種遞迴返回形成了遞推關係，每個 F_n 的值最多被用到兩次，首次是從遞迴呼叫直接返回，再次是對其已儲存的值進行訪問，每個步驟要麼訪問兩項並儲存兩項，要麼訪問一項並儲存一項。故而它可以進一步寫為： 1si 2aq sN dliN lGx dli1dsi2a sM d 2 lFx r 1 lFx sG d1M dsFx 在遞迴定義 F_n F_n1 F_n2 的上述兩種求值次序中，首先進行 F_n1 遞迴呼叫的這種形式，其記憶化實現從一開始就持續進行遞迴呼叫直到首次遞迴返回，然後就逐級遞迴返回而不再進行遞迴呼叫，故而它可以進一步寫為： a 0 F x x 1 G x x G x curt F x1 prev a a curt curt prev 這裡的 a 被初始化為 F_0 的值 0，x 除了在被遞減至 F_1 的值 1 之時作為呼叫結果來返回之外，沒有參與到後續的加法運算之中，而主要起到了遞減計數器的作用。它可實現為： 0sa 1 lFx la r dsa sG d1G dsFx 下面的例子採用迭代法打印出斐波那契數列的不含第 0 項的前 n 項： i x a 1 F x i 0 G x x G x prev a a x x x prev print x i i 1 F x F 0 針對遞推關係 F_n F_n1 F_n2，它總共進行 n 次迭代運算得出 F_1 到 F_n。這裡的 i 是進行迭代的遞減計數器，所迭代的是需要初始化的兩個值 x 和 a：在堆疊中的 x 先是被迭代的 F_n1 再是迭代出的 F_n，其初始值 0 是 F_0；作為全域性變數的 a，以 F_1F_0 所得的 1 作為初始值，在首次迭代之後它是始於 F_0 的 F_n2。它可實現為： si 1sa 0 lardsa p li1si lFx sG li0G dsFx 下面是其執行示例： echo 6 dc e si 1sa 0 lardsa p li1si lFx sG li0G dsFx 1 1 2 3 5 8 可以將它改為計算單個的斐波那契數： echo 0 dc e si 1sa 0 lardsa li1si lFx sG li0G dsFx p 0 echo 9 dc e si 1sa 0 lardsa li1si lFx sG li0G dsFx p 34 參見 bc 逆波蘭表示法 面向堆疊程式設計 隱式程式設計 堆疊機器 引用 外部連結 軟體包 dc 在 Debian GNULinux 倉庫中 bc 的原生 Windows 移植包括了 dc 嵌入到網頁中的 dc The unix dc 1 command this is the esoteric language that made it big Category 面向堆疊程式語言 Category 跨平臺軟體 CategoryUnix 軟體 Category 軟體計算器 Category 自由數學軟體 Category 數值分析語言