bc 命令
用途
为任意精度算术语言提供解释器。
语法
描述
bc 命令是一个提供任意精度算术的交互式进程。 bc 命令首先读取由 File 参数指定的任一输入文件,然后读取标准输入。 输入文件必须是包含 bc 命令能读取并执行的命令序列、语句或函数定义的文本文件。
bc 命令是 dc 命令的预处理程序。 它自动调用 dc 命令,除非指定了 -c (仅编译) 标志。 如果指定了 -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 命令处理来自源文件信息的方式的进一步的信息在以下各节中得到描述:
语法
以下语法描述了 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
/* 'define', 'break', 'quit', 'length' */
%token Return For If While Sqrt
/* 'return', 'for', 'if', 'while', 'sqrt' */
%token Scale Ibase Obase Auto
/* 'scale', 'ibase', 'obase', 'auto' */
%start program
%%
program : EOF
| input_item program
;
input_item : semicolon_list NEWLINE
| function
;
semicolon_list : /* empty */
| statement
| semicolon_list ';' statement
| semicolon_list ';'
;
statement_list : /* empty */
| 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:/* empty */
| parameter_list
;
parameter_list : LETTER
| define_list ',' LETTER
;
opt_auto_define_list
: /* empty */
| Auto define_list NEWLINE
| Auto define_list ';'
;
define_list : LETTER
| LETTER '[' ']'
| define_list ',' LETTER
| define_list ',' LETTER '[' ']'
;
opt_argument_list : /* empty */
| argument_list
;
argument_list : expression
| argument_list ',' expression
;
relational_expression
: expression
| expression REL_OP expression
;
return_expression : /* empty */
| 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 命令:
- bc 命令识别从给定点开始的最长可能的词法标记或定界符。
- 注释以/* (斜杠,星号) 开头,以 */ (星号,斜杠) 结尾。 注释仅对定界词法标记有效。
- 换行符可识别为 NEWLINE 标记。
- STRING 标记表示字符串常量。 字符串以 "(双引号)开头并以 "(双引号)终止。 引号间的所有字符都按照字面取出。 无法指定包含 "(双引号)的字符串。 每个字符串的长度限制为 limits.h 文件中定义的 BC_STRING_MAX 值设置的最大字节数。
- 空白字符不起作用,除非它们出现在 STRING 标记中或用于对词法标记进行定界。
- \n (反斜杠,换行符) 字符:
- 对词法标记进行定界。
- 在 STRING 标记中解释为字符序列。
- 当多行 NUMBER 令牌的一部分时,将忽略 。
- NUMBER 令牌使用以下语法:
NUMBER 标记在 ibase 内部寄存器值指定的进制中解释为数字。NUMBER : integer | '.' integer | integer '.' |integer '.' integer ; integer : digit | integer digit ; digit : 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F ; - NUMBER 令牌的值解释为由 ibase 内部寄存器的值指定的基数中的数字。 每个数字字符具有值 0 到 15(以这里列出的顺序排列),且句号字符表示基点。 如果数字大于或等于出现在标记中的 ibase 寄存器的值,那么行为未定义。 对于指定给 ibase 和 obase 寄存器自己的单个位数的值,有一个例外。
- 以下关键字可识别为令牌:
auto for length return sqrt break ibase obase scale while define if quit - 除非在关键字中,否则下列任何字母都被视为 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 - 以下单字符和双字符序列可识别为 ASSIGN_OP 令牌:
- = (等号)
- + = (加号,等号)
- -= (减号,等号)
- * = (星号,等号)
- /= (斜杠,等号)
- % = (百分比,等号)
- ^ = (插入标记,等号)
- 以下单个字符可识别为 MUL_OP 令牌:
- * (星号)
- /(斜杠)
- % (百分比)
- 以下单字符和双字符序列可识别为 REL_OP 令牌:
- == (双等号)
- <= (less than, equal sign)
- > = (大于,等号)
- ! = (感叹号,等号)
- < (less than)
- > (大于)
- 以下两字符序列可识别为 INCR_DECR 令牌:
- + + (双加号)
- -- (双连字符)
- 以下单个字符可识别为标记。 标记和字符具有相同的名称:
- <newline>
- ((左圆括号)
- )(右圆括号)
- ,(逗号)
- +(加号)
- -(减号)
- ;(分号)
- [(左方括号)
- ](右方括号)
- ^ (插入记号)
- { (左花括号)
- } (右花括号)
- 当到达输入结束时,将返回 EOF 令牌。
标识符和运算符
bc 命令可识别的标识符有三种:普通标识符、数组标识符和函数标识符。 所有三种类型包含单个小写字母。 数组标识符后跟 [ ](左和右方括号)。 除了在参数中或自动列表中,数组下标是必需的。 数组是单维构成的,且最多可包含 BC_DIM_MAX 值指定的数量。 索引从 0 开始。 因此,一个数组的索引范围是从 0 到BC_DIM_MAX -1 所定义的值。 下标截断为整数。 函数标识符必须后跟 ( )(左和右圆括号)并可能包含自变量。 这三种标识符不冲突。
bc 程序表的运算符总结了优先规则和所有运算符的关联性的规则。 同一行上的运算符具有相同的优先权。 行以递减优先顺序排列。
| 运算符 | 关联性 |
|---|---|
| ++, - - | 不适用 |
| 一元 - | 不适用 |
| ^ | 从右至左 |
| *, /, % | 从左至右 |
| + ,二进制- | 从左至右 |
| =, +=, -=, *=, /=, ^= | 从右至左 |
| ==, <=, >=, !=, <, > | 无 |
每个表达式或命名表达式具有一个小数位,它是表达式小数部分要保留的十进制数字的位数。
命名表达式是存储值的位置。 命名表达式在赋值的左边是有效的。 命名表达式的值是存储于指定位置的值。 简单的标识符和数组元素是命名表达式;它们具有一个为零的初始值和一个为零的初始小数位。
内部寄存器 scale、ibase 和 obase 都是命名表达式。 由其中一个寄存器的名称组成的表达式的标度为 0。 分配给任何这些寄存器的值将被截断为整数。 scale 寄存器包含一个用于计算表达式小数位的全局值(如下描述)。 The value of the 标度 register is limited to 0 <= 标度 <= {BC_SCALE_MAX} and has a default value of 0. ibase 和 obase 寄存器分别是输入号和输出号基数。 The value of 伊基 is limited to 2 <= 伊基 <= 16. The value of 奥巴塞 is limited to 2 <= 奥巴塞 = {BC_BASE_MAX}
当为 ibase 或 obase 寄存器分配了 "词法约定" 中描述的列表中的个位数值时,将采用十六进制值。 例如:
ibase=A 设置到底数十,而不考虑当前的 ibase 寄存器值。 其他情况下,如果数字大于或等于出现在输入中的 ibase 寄存器的值,那么行为未定义。 ibase 和 obase 寄存器都具有初始值 10。
内部计算就像十进制(不考虑输入和输出底数)一样进行到指定的小数位个数。 当没有得到精确的结果,例如:
scale=0; 3.2/1
bc 命令截断此结果。
obase 寄存器的所有数字值根据以下规则输出:
- 如果值小于 0 ,那么输出 a-(连字符)。
- 根据数字值输出下列其中一项:
- 如果数字值的绝对值大于或等于 1 ,请将该值的整数部分输出为适合于 obase 寄存器的一系列数字 (在步骤 3 中描述)。 下一步输出最重要的非零数字,每个数后跟连续的较不重要的数字。
- 如果数字值的绝对值小于 1 但大于 0 ,并且数字值的小数位大于 0 ,那么未指定是否输出字符 0。
- 如果数字值为 0 ,那么输出字符 0。
- 如果值的小数位大于 0 ,那么输出 a。 (点)后跟一系列适合以下 obase 寄存器值的数字。 这些数字表示值的小数部分的最重要的部分,且 s 表示正在输出的值的小数位:
- 如果 obase 值为 10 ,那么输出 s 位数。
- 如果 obase 值大于 10 ,那么输出小于或等于 s的数字。
- 如果 obase 值小于 10 ,那么输出大于或等于 s的数字。
- 对于除 10 以外的 obase 值,这应该是表示精度 10s所需的位数。
- 对于从 2 到 16 的 obase 值,有效数字是单个字符的第一个 obase :
这分别表示值 0 到 15。0 1 2 3 4 5 6 7 8 9 A B C D E F - 对于大于 16 的基数,每个数字都写为单独的多位数十进制数。 除了最重要的小数数字,每个数字前有一个空格字符。 对于底数 17 到 100,bc 命令写二位十进制数字,对于底数 101 到 1000,bc 命令写三位的十进制数。 例如,底数 25 的十进制数 1024 将写作:
01 15 24底数 125,如:
008 024
表达式
数字常量是一个表达式。 小数位是表示常量的输入中的小数点后面的数位,或 0(如果没有小数点)。
序列(expression)是具有和 expression 相同值和小数位的表达式。 括号可以用来更改正常的优先顺序。
一元和二目运算符具有以下语义:
| 项 | 描述 |
|---|---|
| -expression | 结果是表达式的负数。 结果的小数位是表达式的小数位。 一元增量和减量运算符不会修改它们运算的命名表达式的小数位。 结果的小数位是该命名表达式的小数位。 |
| + +named_expression | 指定的表达式按 1 递增。 结果是递增后指定表达式的值。 |
| -named_expression | 指定的表达式由 1 递减。 结果是在递减后指定表达式的值。 |
| named_expression+ + | 指定的表达式按 1 递增。 结果是在递增之前指定表达式的值。 |
| named_expression-- | 指定的表达式由 1 递减。 结果是在进行递减之前指定的表达式的值。 |
乘方运算符 ^ (插入记号) 从右至左绑定。
| 项 | 描述 |
|---|---|
| 表达式 ^表达式 | 结果是 expression 升到第二个 expression 的乘幂。 如果第二个表达式不是整数,那么行为未定义。 如果a是左表达式的刻度,b是正确表达式的绝对值,结果的尺度是: |
乘法运算符 *(星号)、/(斜杠)和 %(百分号)从左至右绑定。
| 项 | 描述 |
|---|---|
| expression * 表达式 | 结果是两个表达式的乘积。 如果a和b是两个表达式的刻度,那么结果的刻度是: |
| 表达式 / 表达式 | 结果是两个表达式的商。 结果的小数位是 scale 的值。 |
| expression % 表达式 | 用于表达式a和b,a % b求值结果相当于以下步骤:
|
加法运算符 +(加号)和 -(减号)从左至右绑定。
| 项 | 描述 |
|---|---|
| expression + 表达式 | 结果是两个表达式的和。 结果的小数位是表达式的小数位的最大值。 |
| expression - expression | 结果是两个表达式的差。 结果的小数位是表达式的小数位的最大值。 |
以下赋值运算符从右到左绑定:
- =(等号)
- +=(加号、等号)
- -=(减号、等号)
- *=(星号、等号)
- /=(斜杠、等号)
- %=(百分号、等号)
- ^=(插入记号、等号)
| 项 | 描述 |
|---|---|
| named-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 为 false 时,执行在 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 标志时,定义以下函数:
| 项 | 描述 |
|---|---|
| (expression) | 指定 expressionx 的正弦,其中 expression 是弧度。 |
| c (表达式) | 指定 expressionx 的余弦,其中 expression 是弧度。 |
| a (expression) | 指定 expressionx 的反正切,其中 expression 是弧度。 |
| l (expression) | 指定 expression 的自然对数。 |
| e (表达式) | 指定 expression 的幂。 |
| j (expression,expression) | 指定整数顺序的 Bessel 函数。 |
当调用函数时,对这些函数的每一个的调用的小数位是 scale 关键字的值。 如果用数学函数域之外的自变量来调用这些函数中的任何一个,那么行为未定义。
标志
| 项 | 描述 |
|---|---|
| -c | 编译 File 参数,但不调用 dc 命令。 |
| -l | (小写 L)定义数学函数的库,并将 scale 变量设置为 20。 |
退出状态
本命令返回以下退出值:
| 项 | 描述 |
|---|---|
| 重大安全事件数量 | 成功完成。 |
| 第 1 年 | 遇到语法错误或不能访问输入文件。 |
| 未指定 | 有其他错误发生。 |
示例
- 可以使用 bc 命令作为计算器。 根据您是否设置了 scale 变量以及设置了什么值,系统显示小数数量。 请输入:
仅显示0. 要设置 scale 变量并添加注释,请输入:bc 1/4
屏幕显示0.2. 输入:scale = 1 /* Keep 1 decimal place */ 1/4
显示0.250. 输入:scale = 3 /* Keep 3 decimal places */ 1/4
显示28.600. 输入16+63/5
显示15.800. 输入(16+63)/5
显示11.833.71/6当按下 Enter 键时,bc 命令显示除了赋值以外的每个表达式的值。
当从键盘直接输入 bc 命令表达式,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。
- 要编写并运行类似 C 语言的程序,请输入类似于以下命令的命令:屏幕显示7.38905609893065022723. 如果输入:
屏幕显示120. 如果输入:f(5) /* 5 factorial */
屏幕显示3628800.f(10) /* 10 factorial */此序列解释保存在 prog.bc 文件中的 bc 程序,并从键盘读取更多的 bc 命令语句。 使用 -l 标志启动 bc 命令使数学库可用。 此示例使用数学库中的 e (指数) 函数,并且f在 prog.bc 程序文件中定义为:
跟在 for 或 while 语句后的语句必须在同一行开始。 当从键盘直接输入 bc 命令表达式,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。/* compute the factorial of n */ define f(n) { auto i, r; r = 1; for (i=2; i<=n; i++) r =* i; return (r); } - 要将中缀表达式转换为“逆向 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 命令以后通过重定向此命令的标准输出来求值。 当从键盘直接输入 bc 命令表达式,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。
- 要在 shell 中将 pi 的前 10 位数的近似值指定给变量 x,请输入:
以下 bc 程序将 pi 的相同近似值(带有标号)打印到标准输出:x=$(printf "%s\n" 'scale = 10; 104348/33215' | bc)scale = 10 "pi equals " 104348 / 33215 - 要定义一个函数来计算指数函数(如果指定了 -l(小写 L)选项则此类函数为预定义的)的近似值,请输入:
要打印前 10 个整数的指数函数的近似值,请输入: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 } }for (i = 1; i <= 10; ++i) { e(i) }
文件
| 项 | 描述 |
|---|---|
| /usr/bin/bc | 包含 bc 命令。 |
| /usr/lib/lib.b | 包含数学库。 |
| /usr/bin/dc | 包含桌面计算器。 |