bc

BC命令

徠bc為任意精度算術語言提供解釋器。BC的含義是:Binary Calculator,用於實現任意精度計算(往往是高精度計算)。

基本介紹


LINUX命令
語法
bc [ -c ] [ -l ] [ File ... ]
描述
bc 命令是一個提供任意精度算術的互動式進程。bc 命令首先讀取由 File 參數指定的任一輸入文件,然後讀取標準輸入。輸入文件必須是包含 bc 命令能讀取並執行的命令序列、語句或函數定義的文本文件。
bc 命令是 dc 命令的預處理程序。除非指定 -c(僅編譯)標誌,否則它自動調用 dc 命令。如果指定了 -c 標誌,則來自 bc 命令的輸出轉到標準輸出。
bc 命令允許您來指定十進位、八進位或十六進位的運算的輸入和輸出進位。預設值為十進位。此命令還提供了十進位點符號的比例縮放規定。bc 命令始終使用 .(點號)來表示基數點,而不考慮指定為當前語言環境部分的任何十進位點字元。
bc 命令的語法類似於 C 語言的語法。可以使用 bc 命令通過將 ibase 關鍵字指定給輸入進位而 obase 關鍵字指定給輸出進位來在各進位間轉化。2 到 16 的範圍對於 ibase 關鍵字是有效的。obase 關鍵字的範圍從 2 直到 /usr/include/sys/limits.h文件中定義的 BC_BASE_MAX 值設置的限制。不考慮 ibase 和 obase 的設置,bc 命令將字母 A 到 F 識別為其十六進位值 10 到 15。
bc 命令的輸出由讀取程序控制。輸出由包含所有執行的未賦值表達式的值的一行或多行構成。輸出的基數和精度由 obase 和 scale 關鍵字的值控制。
有關 bc 命令處理來自源文件信息的方式的進一步的信息在以下各節中得到描述:
* 語法
* 詞法約定
*標識符和運算符
* 表達式
* 語句
* 函數調用
* -I 數學庫中的函數
語法
以下語法描述了 bc 程序的語法,其中 program 代表任何有效的程序:
%token EOF NEWLINE STRING LETTER NUMBER
%token MUL_OP
%token ASSIGN_OP
%token REL_OP
%token INCR_DECR
%token Define Break Quit Length
%token Return For If While Sqrt
%token Scale Ibase Obase Auto
%start program
%%
program : EOF
| input_item program
;
input_item : semicolon_list NEWLINE
| function
;
semicolon_list :
| statement
| semicolon_list ';' statement
| semicolon_list ';'
;
statement_list :
| statement
| statement_list NEWLINE
| statement_list NEWLINE statement
| statement_list ';'
| statement_list ';' statement
;
statement : expression
| STRING
| Break
| Quit
| Return
| Return '(' return_expression ')'
| For '(' expression ';'
relational_expression ';'
expression ')' statement
| If '(' relational_expression ')' statement
| While '(' relational_expression ')' statement
| '{' statement_list '}'
;
function : Define LETTER '(' opt_parameter_list ')'
'{' NEWLINE opt_auto_define_list
statement_list '}'
;
opt_parameter_list:
| parameter_list
;
parameter_list : LETTER
| define_list ',' LETTER
;
opt_auto_define_list
:
| Auto define_list NEWLINE
| Auto define_list ';'
;
define_list : LETTER
| LETTER '[' ']'
| define_list ',' LETTER
| define_list ',' LETTER '[' ']'
;
opt_argument_list :
| argument_list
;
argument_list : expression
| argument_list ',' expression
;
relational_expression
: expression
| expression REL_OP expression
;
return_expression :
| expression
;
expression : named_expression
| NUMBER
| '(' expression ')'
| LETTER '(' opt_argument_list ')'
| '-' expression
| expression '+' expression
| expression '-' expression
| expression MUL_OP expression
| expression '^' expression
| INCR_DECR named_expression
| named_expression INCR_DECR
| named_expression ASSIGN_OP expression
| Length '(' expression ')'
| Sqrt '(' expression ')'
| Scale '(' expression ')'
;
named_expression : LETTER
| LETTER '[' expression ']'
| Scale
| Ibase
| Obase
;
詞法約定
以下詞法約定適用於 bc 命令:
1. bc 命令識別最長的可能的詞法標記或在給定點開始的定界符。
2. 以 (星號、斜杠)結束的註釋。註釋僅對定界詞法標記有效。
3. 將換行字元識別為 NEWLINE 標記。
4. STRING 標記表示一個字元串常量。字元串以 "(雙引號)開頭並以 "(雙引號)終止。引號間的所有字元都按照字面取出。無法指定包含 "(雙引號)的字元串。每個字元串的長度限制為 limits.h 文件中定義的 BC_STRING_MAX 值設置的最大位元組數。
5. 空白字元僅當出現在 STRING 標誌中或用來定界詞法標記時才有效。
6. \n(反斜杠、換行)字元:
* 定界詞法標記。
* 解釋為 STRING 標記中的一個字元序列。
* 當作為多行 NUMBER 標記的一部分時被忽略。
7. NUMBER 標記使用以下語法:
NUMBER : integer
| '.' integer
| integer '.'
|integer '.' integer
;
integer : digit
| integer digit
;
| 8 | 9 | A | B | C | D | E | F
;
NUMBER 標記在 ibase 內部寄存器值指定的進位中解釋為數字。
8. NUMBER 標記的值解釋為由 ibase 內部寄存器的值指定的進位的數字。每個數字字元具有值 0 到 15(以這裡列出的順序排列),且句號字元表示基點。如果數字大於或等於出現在標記中的 ibase 寄存器的值,則行為未定義。對於指定給 ibase 和 obase 寄存器自己的單個位數的值,有一個例外。
9. 將以下關鍵字識別為標記:
auto for length return sqrt
break ibase obase scale while
define if quit
10. 除了在關鍵字中,以下任何字母都看作是一個 LETTER 標記:
a b c d e f g h i j k l m n o p q r s t u v w x y z
11. 將以下單字元和雙字元序列識別為 ASSIGN_OP 標記:
* =(等號)
* +=(加號、等號)
* -=(減號、等號)
* *=(星號、等號)
* /=(斜杠、等號)
* %=(百分號、等號)
* ^=(插入記號、等號)
12. 將以下單字元識別為 MUL_OP 標記:
* *(星號)
* /(斜杠)
* %(百分號)
13. 將以下單字元和雙字元序列識別為 REL_OP 標記:
* ==(雙等號)
* <=(小於號、等號)
* >=(大於號、等號)
* !=(感嘆號、等號)
* <(小於號)
* >(大於號)
14. 將以下雙字元序列識別為 INCR_DECR 標記:
* ++(雙加號)
* --(雙連字元)
15. 將以下單字元識別為標記。標記和字元具有相同的名稱:
((左圓括弧)
)(右圓括弧)
,(逗號)
+(加號)
-(減號)
;(分號)
[(左方括弧)
](右方括弧)
^ (插入記號)
{ (左花括弧)
} (右花括弧)
16. 當到達輸入末尾時,返回 EOF 標記。
標識符和運算符
bc 命令可識別的標識符有三種:普通標識符、數組標識符和函數標識符。所有三種類型包含單個小寫字母。數組標識符後跟 [ ](左和右方括弧)。除了在參數中或自動列表中,數組下標是必需的。數組是單維構成的,且最多可包含 BC_DIM_MAX 值指定的數量。索引從 0 開始。所以數組從 0 開始建立索引值到 BC_DIM_MAX -1 定義的值。下標截斷為整數。函數標識符必須後跟 ( )(左和右圓括弧)並可能包含自變數。這三種標識符不衝突。
bc 程序表的運算符總結了優先規則和所有運算符的關聯性的規則。同一行上的運算符具有相同的優先權。行以遞減優先順序排列。
bc 程序中的運算符
運算符 關聯性
++, - - 不適用
unary - 不適用
^ 從右至左
*, /, % 從左至右
+,二進位 - 從左至右
=, +=, -=, *=, /=, ^= 從右至左
==, <=, >=, !=, <, > 無
每個表達式或命名表達式具有一個小數位,它是表達式小數部分要保留的十進位數字的位數。
命名表達式是存儲值的位置。命名表達式在賦值的左邊是有效的。命名表達式的值是存儲於指定位置的值。簡單的標識符和數組元素是命名表達式;它們具有一個為零的初始值和一個為零的初始小數位。
內部寄存器 scale、ibase 和 obase 都是命名表達式。包含這些寄存器之一的名稱的表達式的小數位是 0。指定給這些寄存器任意之一的值將截斷為整數。scale 寄存器包含一個用於計算表達式小數位的全局值(如下描述)。scale 寄存器的值限制為 0 <= scale <= 並具有一個預設值 0。ibase 和 obase 寄存器分別是輸入和輸出數字的基數。ibase 的值限制為 2 <= ibase <= 16。obase 的值限制為 2 <= obase = 。
當為 ibase 或 obase 寄存器指定了“詞法約定”中描述的列表中的單個位數的值時,該值假定為十六進位。例如:
ibase=A
設置到底數十,而不考慮當前的 ibase 寄存器值。其它情況下,如果數字大於或等於出現在輸入中的 ibase 寄存器的值,則行為未定義。ibase 和 obase 寄存器都具有初始值 10。
內部計算就像十進位(不考慮輸入和輸出底數)一樣進行到指定的小數位個數。當沒有得到精確的結果,例如:
scale=0; 3.2/1
bc 命令截斷此結果。
o徠base 寄存器的所有數字值根據以下規則輸出:
1. 如果值小於 0,輸出 -(連字元)。
2. 輸出以下內容之一,這取決於數字值:
* 如果數字值的絕對值大於或等於 1,則輸出作為適合 obase 寄存器的一系列數字的值的整數部分(在步驟 3 中描述)。下一步輸出最重要的非零數字,每個數後跟連續的較不重要的數字。
* 如果數字值的絕對值小於 1 但大於 0,且數字值的小數位大於 0,則不指定是否輸出字元 0。
* 如果數字值是 0,則輸出字元 0。
3. 如果該值的小數位大於 0,則輸出 .(點號)後跟一系列適合以下 obase 寄存器值的數字。這些數字錶示值的小數部分的最重要的部分,且 s 表示正在輸出的值的小數位:
* 如果 obase 值是 10,則輸出 s 位的數字。
* 如果 obase 值大於 10,輸出小於或等於 s 位的數字。
* 如果 obase 值小於 10,則輸出大於或等於 s 位的數字。
* 對於值不是 10 的 obase 值,這應該是要表示 10 的精度所需的數位。
* 對於值為 2 到 16 的 obase 值,有效的數字是單字元的第一個 obase:
0 1 2 3 4 5 6 7 8 9 A B C D E F
這分別表示值 0 到 15。
* 對於大於 16 的底數,每個數字寫作分開的多位數的十進位數字。除了最重要的小數數字,每個數字前有一個空格字元。對於底數 17 到 100,bc 命令寫二位十進位數字,對於底數 101 到 1000,bc 命令寫三位的十進位數。例如,底數 25 的十進位數 1024 將寫作:
01 15 24
底數 125,如:
008 024
超大數字分行分割,在 POSIX 語言環境中每行 70 個字元。其它語言環境可能在不同的字元邊界分割。要繼續的行必須以 \ (反斜杠) 結束。
表達式
數字常量是一個表達式。小數位是表示常量的輸入中的小數點後面的數位,或 0(如果沒有小數點)。
序列(expression)是具有和 expression 相同值和小數位的表達式。括弧可以用來更改正常的優先順序。
一元和二元運算符具有以下語義:
-expression 結果是表達式的負數。結果的小數位是表達式的小數位。
一元增量和減量運算符不會修改它們運算的命名表達式的小數位。結果的小數位是該命名表達式的小數位。
++named_expression 命名表達式按 1 遞增。結果就是增量后的命名表達式的值。
- -named_expression 命名表達式按 1 遞減。結果就是減量后的命名表達式的值。
named_expression++ 命名表達式按 1 遞增。結果就是增量前的命名表達式的值。
named_expression- - 命名表達式按 1 遞減。結果就是減量前的命名表達式的值。
乘方運算符 ^ (插入記號) 從右至左綁定。
expression ^expression 結果是 expression 升到第二個 expression 的乘冪。如果第二個表達式不是整數,則行為未定義。如果 a 是左邊表達式的小數位且 b 是右邊表達式的絕對值,則結果的小數位是:
if b >= 0 min(a * b, max(scale, a))
if b < 0 scale
乘法運算符 *(星號)、/(斜杠)和 %(百分號)從左至右綁定。
expression * expression 結果是兩個表達式的乘積。如果 a 和 b 是兩個表達式的小數位,則結果的小數位是:
min(a+b,max(scale,a,b))
expression / expression 結果是兩個表達式的商。結果的小數位是 scale 的值。
expression % expression 對於表達式 a 和 b,a % b 等同以下步驟來求值:
1. 計算 a/b,保留當前小數位。
2. 請使用結果來計算:
a - (a / b) * b
至小數位:
max(scale + scale(b), scale(a))
結果的小數位將是:
max(scale + scale(b), scale(a))
當 scale 為零時,% 運算符是數學餘數運算符。
加法運算符 +(加號)和 -(減號)從左至右綁定。
expression + expression 結果是兩個表達式的和。結果的小數位是表達式的小數位的最大值。
expression - expression 結果是兩個表達式的差。結果的小數位是表達式的小數位的最大值。
以下賦值運算符從右到左綁定:
* =(等號)
* +=(加號、等號)
* -=(減號、等號)
* *=(星號、等號)
* /=(斜杠、等號)
* %=(百分號、等號)
* ^=(插入記號、等號)
named-expression = expression 這個表達式最終將右邊的表達式的值指定給左邊的命名表達式。命名表達式和結果的小數位都是表達式的小數位。
複合賦值格式:
named-expression = expression
等同於:
named-expression = named-expression expression
除了命名表達式僅求值一次。
與其它所有運算符不同,以下關係運算符僅作為 if 或 while 語句的對象或在 for 語句中時才有效:
* <(小於號)
* >(大於號)
* <=(小於號、等號)
* >=(大於號、等號)
* ==(雙等號)
* !=(感嘆號、等號)
expression1 < expression2 如果 expression1 的值嚴格小於 expression2 的值,則關係為真。
expression1 > expression2 如果 expression1 的值嚴格大於 expression2 的值,則關係為真。
expression1 <= expression2 如果 expression1 的值小於或等於 expression2 的值,則關係為真。
expression1 >= expression2 如果 expression1 的值大於或等於 expression2 的值,則關係為真。
expression1 == expression2 如果 expression1 的值和 expression2 的值相等,則關係為真。
expression1 != expression2 如果 expression1 的值和 expression2 的值不相等,則關係為真。
語句
當語句是一個表達式時,除非主運算符是一個賦值,否則語句的執行寫出表達式的值後跟一個換行字元。
當語句是一個字元串時,語句的執行寫出字元串的值。
以分號或換行字元隔開的語句按序執行。在 bc 命令的互動式調用中,每次讀取一個滿足語法生成的換行字元:
input_item : semicolon_list NEWLINE
構成 semicolon_list 的語句的有序列表將立即執行,且該執行產生的任何輸出寫出時沒有任何緩衝區延遲。
如果是 if 語句(if (relation) statement),則當關係為真時執行該 statement。
while 語句(while (relation) statement)實現其中測試 relation 的循環。每次 relation 為真時,則執行statement 並測試 relation。當 relation 為假時,執行在 statement 之後恢復。
for 語句(for (expression; relation; expression) statement)與下面形式相同:
first-expression
while (relation) {
statement
last-expression
}
所有三個表達式都必須存在。
break 語句使 for 或 while 語句終止。
auto 語句(auto identifier [,identifier ] ...)使標識符的值減小。標識符可以是普通標識符或數組標識符。數組標識符由後跟空的方括弧的數組名指定。auto 語句必須是在函數定義中的第一個語句。
define 語句:
define LETTER ( opt_parameter_list ) {
opt_auto_define_list
statement_list
}
定義名為 LETTER 的函數。如果先前定義了 LETTER 函數,則 define 語句取代先前的定義。表達式:
LETTER ( opt_argument_list )
調用 LETTER 函數。如果調用中自變數的數量與定義中參數的數量不匹配,則行為未定義。在調用函數之前先定義它。函數看作是在它自己主體內定義,這樣循環調用就是有效的。當調用函數時,函數內數字常量值以 ibase 寄存器的值指定的底數來解釋。
return 語句(return 和 return (expression))使函數終止,彈出它的 auto 變數,並指定函數的結果。第一個格式等同於返回 0。函數的調用的值和小數位是括弧中表達式的值和小數位。
quit 語句(quit)在輸入中的語句出現位置停止 bc 程序的執行,即使它出現在函數定義中或出現在 if、for 或 while 語句中。
函數調用
函數調用由函數名稱,後跟包含在括弧內的以逗號隔開的表達式列表(這些表達式是函數自變數)組成。作為自變數傳遞的整個數組由後跟 [ ](左方括弧和右方括弧)的數組名稱指定。所有函數自變數按值傳遞。所以對形式參數的更改不會影響實際參數的效果。如果函數通過執行 return 語句終止,則函數的值是 return 語句的圓括弧中的表達式的值,或如果不提供表達式或沒有 return 語句則為零。
sqrt(expression) 的結果是表達式的平方根。結果在最不重要的小數位置截斷。結果的小數位是表達式的小數位或 scale 的值中較大的一個。
length(expression) 的結果是表達式中重要十進位數的總數。結果的小數位是 0。
scale(expression) 的結果是表達式的小數位。結果的小數位是 0。
bc 程序中僅有兩種存儲類,即全局和自動(本地)。只有對函數而言是本地的標識符需要用 auto 關鍵字說明。函數的自變數對函數而言是本地的。所有其它標識符假定為全局並可用於所有函數。所有標識符,全局和本地,具有初始值 0。聲明為 auto 的標識符在進入函數時分配並在從函數返回時釋放。所以它們不在函數調用之間保留值。auto 數組由後跟 [](左方括弧、右方括弧)的數組名指定。進入函數時,作為參數和自動變數出現的名稱的舊值被推上堆棧。函數返回之前,對這些名稱的引用僅引用新值。
在那些函數之一使用本地變數的同一個名稱之前,從此函數調用的其它函數對這些名稱中的任何一個的引用也引用新值。
-l 數學庫中的函數
當指定 -l 標誌時,定義以下函數:
s(expression) 指定 expressionx 的正弦,其中 expression 是弧度。
c(expression) 指定 expressionx 的餘弦,其中 expression 是弧度。
a(expression) 指定 expressionx 的反正切,其中 expression 是弧度。
l(expression) 指定 expression 的自然對數
e(expression) 指定 expression 的冪。
j(expression,expression)
指定整數順序的 Bessel 函數。
當調用函數時,對這些函數的每一個的調用的小數位是 scale 關鍵字的值。如果用數學函數域之外的自變數來調用這些函數中的任何一個,則行為未定義。
標誌
-c 編譯 File 參數,但不調用 dc 命令。
-l (小寫 L)定義數學函數的庫,並將 scale 變數設置為 20。
退出狀態
該命令返回以下退出值:
0 成功完成。
1 遇到語法錯誤或不能訪問輸入文件。
unspecified 有其它錯誤發生。
示例
1. 可以使用 bc 命令作為計算器。根據您是否設置了 scale 變數以及設置了什麼值,系統顯示小數數量。請輸入:
bc
1/4
僅顯示 0。要設置 scale 變數並添加註釋,請輸入:
scale = 1
1/4
屏幕顯示 0.2。輸入:
scale = 3
1/4
顯示 0.250。輸入:
16+63/5
顯示 28.600。輸入:
(16+63)/5
顯示 15.800。輸入:
71/6
顯示 11.833。
當按下 Enter 鍵時,bc 命令顯示除了賦值以外的每個表達式的值。。
2. 要編寫並運行類似 C 語言的程序,請輸入類似於以下命令的命令:
bc -l prog.bc
e(2)
ma
屏幕顯示 7.38905609893065022723。如果輸入:
f(5)
屏幕顯示 120。如果輸入:
f(10)
屏幕顯示 3628800。
此序列解釋保存在 prog.bc 文件中的 bc 程序,並從鍵盤讀取更多的 bc 命令語句。用 -l 標誌啟動 bc 命令將使數學庫可用。此示例使用來自數學庫中的 e(冪)函數,且 f 在 prog.bc 程序文件中定義為:
define f(n) {
auto i, r;
r = 1;
for (i=2; i<=n; i++) r =* i;
return (r);
}
跟在 for 或 while 語句后的語句必須在同一行開始。當從鍵盤直接輸入 bc 命令表達式時,請
3. 要將中綴表達式轉換為“逆向 Polish 表示法”(Reverse Polish Notation,RPN),請輸入:
bc -c
(a * b) % (3 + 4 * c)
屏幕顯示:
lalb* 3 4lc*+%ps.
此序列將 bc 命令中綴表示表達式編譯為 dc 命令可以解釋的表達式。dc 命令對擴展 RPN 表達式求值。在編譯后的輸出中,每個變數名稱前的 l 是將變數的值裝入到堆棧上的 dc 子命令。p 顯示在堆棧頂端的值,s. 通過將頂端的值存儲在寄存器 .(點)來廢棄它。可以將 RPN 表達式保存在文件中以使 dc 命令以後通過重定向此命令的標準輸出來求值。
4. 要在 shell 中將 pi 的前 10 位數的近似值指定給變數 x,請輸入:
x=$(printf "%s\n" 'scale = 10; 104348/33215' | bc)
以下 bc 程序將 pi 的相同近似值(帶有標號)列印到標準輸出:
scale = 10
"pi equals "
104348 / 33215
5. 要定義一個函數來計算冪函數(如果指定了 -l(小寫 L)選項則此類函數為預定義的)的近似值,請輸入:
scale = 20
define e(x){
auto a, b, c, i, s
a = 1
b = 1
s = 1
for (i = 1; 1 == 1; i++){
a = a*x
b = b*i
c = a/b
if (c == 0) {
return(s)
}
s = s+c
}
}
要列印前 10 個整數的冪函數的近似值,請輸入:
for (i = 1; i <= 10; ++i) {
e(i)
}
文件
/usr/bin/bc 包含 bc 命令。
/usr/lib/lib.b 包含數學庫。
/usr/bin/dc 包含桌面計算器。