为任意精度算术语言提供解释器。
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 命令处理来自源文件信息的方式的进一步的信息在以下各节中得到描述:
以下语法描述了 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 命令:
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 内部寄存器值指定的进制中解释为数字。
auto for length return sqrt break ibase obase scale while define if quit
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
bc 命令可识别的标识符有三种:普通标识符、数组标识符和函数标识符。所有三种类型包含单个小写字母。数组标识符后跟 [ ](左和右方括号)。除了在参数中或自动列表中,数组下标是必需的。数组是单维构成的,且最多可包含 BC_DIM_MAX 值指定的数量。索引从 0 开始。所以数组从 0 开始建立索引值到 BC_DIM_MAX -1 定义的值。下标截断为整数。函数标识符必须后跟 ( )(左和右圆括号)并可能包含自变量。这三种标识符不冲突。
bc 程序表的运算符总结了优先规则和所有运算符的关联性的规则。同一行上的运算符具有相同的优先权。行以递减优先顺序排列。
bc 程序中的运算符 | |
运算符 | 关联性 |
++, - - | 不适用 |
unary - | 不适用 |
^ | 从右至左 |
*, /, % | 从左至右 |
+,二进制 - | 从左至右 |
=, +=, -=, *=, /=, ^= | 从右至左 |
==, <=, >=, !=, <, > | 无 |
每个表达式或命名表达式具有一个小数位,它是表达式小数部分要保留的十进制数字的位数。
命名表达式是存储值的位置。命名表达式在赋值的左边是有效的。命名表达式的值是存储于指定位置的值。简单的标识符和数组元素是命名表达式;它们具有一个为零的初始值和一个为零的初始小数位。
内部寄存器 scale、ibase 和 obase 都是命名表达式。包含这些寄存器之一的名称的表达式的小数位是 0。指定给这些寄存器任意之一的值将截断为整数。scale 寄存器包含一个用于计算表达式小数位的全局值(如下描述)。scale 寄存器的值限制为 0 <= scale <= {BC_SCALE_MAX} 并具有一个缺省值 0。ibase 和 obase 寄存器分别是输入和输出数字的基数。ibase 的值限制为 2 <= ibase <= 16。obase 的值限制为 2 <= obase = {BC_BASE_MAX} 。
当为 ibase 或 obase 寄存器指定了“词法约定”中描述的列表中的单个位数的值时,该值假定为十六进制。例如:
ibase=A
设置到底数十,而不考虑当前的 ibase 寄存器值。其它情况下,如果数字大于或等于出现在输入中的 ibase 寄存器的值,则行为未定义。ibase 和 obase 寄存器都具有初始值 10。
内部计算就像十进制(不考虑输入和输出底数)一样进行到指定的小数位个数。当没有得到精确的结果,例如:
scale=0; 3.2/1
bc 命令截断此结果。
obase 寄存器的所有数字值根据以下规则输出:
0 1 2 3 4 5 6 7 8 9 A B C D E F
这分别表示值 0 到 15。
01 15 24
底数 125,如:
008 024
数字常量是一个表达式。小数位是表示常量的输入中的小数点后面的数位,或 0(如果没有小数点)。
序列(expression)是具有和 expression 相同值和小数位的表达式。括号可以用来更改正常的优先顺序。
一元和二元运算符具有以下语义:
乘方运算符 ^ (插入记号) 从右至左绑定。
expression ^expression | 结果是 expression 升到第二个 expression 的乘幂。如果第二个表达式不是整数,则行为未定义。如果 a 是左边表达式的小数位且 b 是右边表达式的绝对值,则结果的小数位是:
if b >= 0 min(a * b, max(scale, a)) if b < 0 scale |
乘法运算符 *(星号)、/(斜杠)和 %(百分号)从左至右绑定。
加法运算符 +(加号)和 -(减号)从左至右绑定。
expression + expression | 结果是两个表达式的和。结果的小数位是表达式的小数位的最大值。 |
expression - expression | 结果是两个表达式的差。结果的小数位是表达式的小数位的最大值。 |
以下赋值运算符从右到左绑定:
named-expression = expression | 这个表达式最终将右边的表达式的值指定给左边的命名表达式。命名表达式和结果的小数位都是表达式的小数位。 |
复合赋值格式:
named-expression <operator >= expression
等同于:
named-expression = named-expression <operator > expression
除了命名表达式仅求值一次。
与其它所有运算符不同,以下关系运算符仅作为 if 或 while 语句的对象或在 for 语句中时才有效:
当语句是一个表达式时,除非主运算符是一个赋值,否则语句的执行写出表达式的值后跟一个换行字符。
当语句是一个字符串时,语句的执行写出字符串的值。
以分号或换行字符隔开的语句按序执行。在 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 标志时,定义以下函数:
当调用函数时,对这些函数的每一个的调用的小数位是 scale 关键字的值。如果用数学函数域之外的自变量来调用这些函数中的任何一个,则行为未定义。
-c | 编译 File 参数,但不调用 dc 命令。 |
-l | (小写 L)定义数学函数的库,并将 scale 变量设置为 20。 |
该命令返回以下退出值:
0 | 成功完成。 |
1 | 遇到语法错误或不能访问输入文件。 |
unspecified | 有其它错误发生。 |
bc 1/4
仅显示 0。要设置 scale 变量并添加注释,请输入:
scale = 1 /* Keep 1 decimal place */ 1/4
屏幕显示 0.2。输入:
scale = 3 /* Keep 3 decimal places */ 1/4
显示 0.250。输入:
16+63/5
显示 28.600。输入:
(16+63)/5
显示 15.800。输入:
71/6
显示 11.833。
当按下 Enter 键时,bc 命令显示除了赋值以外的每个表达式的值。
当从键盘直接输入 bc 命令表达式,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。
f(5) /* 5 factorial */
屏幕显示 120。如果输入:
f(10) /* 10 factorial */
屏幕显示 3628800。
此序列解释保存在 prog.bc 文件中的 bc 程序,并从键盘读取更多的 bc 命令语句。用 -l 标志启动 bc 命令将使数学库可用。此示例使用来自数学库中的 e(幂)函数,且 f 在 prog.bc 程序文件中定义为:
/* compute the factorial of n */ define f(n) { auto i, r; r = 1; for (i=2; i<=n; i++) r =* i; return (r); }
跟在 for 或 while 语句后的语句必须在同一行开始。当从键盘直接输入 bc 命令表达式时,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。
lalb* 3 4lc*+%ps.
此序列将 bc 命令中缀表示表达式编译为 dc 命令可以解释的表达式。dc 命令对扩展 RPN 表达式求值。在编译后的输出中,每个变量名称前的 l 是将变量的值装入到堆栈上的 dc 子命令。p 显示在堆栈顶端的值,s. 通过将顶端的值存储在寄存器 .(点)来废弃它。可以将 RPN 表达式保存在文件中以使 dc 命令以后通过重定向此命令的标准输出来求值。当从键盘直接输入 bc 命令表达式,请按文件结束符(Ctrl-D)按键顺序来结束 bc 命令会话并返回至 shell 命令行。
x=$(printf "%s\n" 'scale = 10; 104348/33215' | bc)
以下 bc 程序将 pi 的相同近似值(带有标号)打印到标准输出:
scale = 10 "pi equals " 104348 / 33215
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 | 包含桌面计算器。 |