bc

任意精度的算术运算语言


语法格式

bc [-ilqsw] [files]
bc [-h|--help] [-v|--version]

命令简介

bc是一种解释语言,支持任意精度的数值计算,既可以交互运行,也可以采用批处理的方式运行脚本。其中,files是由bc语句组成的一个或一组脚本文件。

在交互运行模式中(未指定files参数)没有任何提示符,可以直接输入算术运算表达式,按下Enter键之后即可获得计算结果。类似于bash,bc命令本身也支持行编辑功能,利用上下箭头键可以调出先前输入的表达式,使用左右箭头键可以移动光标,使用空格和Delete键可以删除字符等。当需要退出bc命令时可输入quit命令,或按下Ctrl-C组合键终止bc命令的执行(也可以使用Ctrl-C组合键终止以批处理方式运行的bc命令)。

bc采用类似于C语言的语法,但语句非常简单。利用命令行选项可以选用标准的数学库函数。如果需要,可在处理任何文件之前定义数学库函数(参见“-l”选项)。一经开始,bc首先会依序处理命令行上的所有文件中的代码。在处理完所有文件之后,bc开始读取标准输入(除非某个文件中含有终止bc执行的命令),处理读入的所有代码。

注意,这里介绍的bc命令包含若干扩充的特性,超出了bc的传统实现与POSIX草案标准。在命令行中增加“-w”选项之后,如果使用的特性属于扩充部分,bc命令将会输出警告或拒绝接受(如果当前的版本不支持)信息。

命令选项

-i, --interactive  强制进入交互模式。

-l, --mathlib  指定标准的数学库。

-q, --quiet  禁止显示常规的GNU欢迎信息。

-s, --standard  严格按照POSIX的标准运行bc。

-w, --warn  遇到POSIX标准的扩展特性时显示警告信息。

数值

在bc中,最基本的元素是数值,包括整数部分和小数部分,数值可以是任意精度的。所有的数值均采用十进制数值表示,计算也是如此。数值具有两种属性:长度和精度。长度指的是数值全部有效数字的位数,精度是小数点后面所有数字的位数。例如,数值.000001的长度为6,精度也为6,1935.000的长度为7,精度为3。

变量

变量是一种命名的存储单元,用于存储数值或引用其中的数值。变量分为普通变量和数组变量。变量名以字母开始,后面可以跟有任意数量的字母、数字和下画线。所有的字母必须是小写字母。数组变量后面附加一对方括号。方括号中的表达式是数组的下标或索引。

一个简单的变量只是一个标识符:

name

而数组变量具有下列形式:

name[expr]

bc具有4个特殊的变量:scale、ibase、obase和last。scale定义了某些运算怎样确定小数点后面的位数,其默认值是0。ibas和obase定义了转换输入和输出数值的进位制,默认的进位制是十。last含有最近一次输出的数值。上述4个变量均可赋予必要的值,也可以用于表达式。

注释

在bc语言中,注释以“/*”字符开始,直至“*/”字符结束。注释可以出现在任何位置,但不能影响其他元素的解析。注释中可以含有换行符,即以多行形式存在。

为了支持脚本,bc也支持单行注释。单行注释以“#”字符开始,直至遇到换行符。但换行符并非单行注释的一部分。

表达式

bc语言的基本组成单位是表达式和语句。bc语言是交互式的,没有“主程序”的概念,除了函数定义之外,表达式或语句的输入一结束(如遇到行终止符),立即解释执行。

最简单的表达式是一个常数。按照ibase变量设定的进位制,bc把输入的常数转换成内部的数据表示。ibase变量的合法取值是2~16,因此,输入的数字可以包含字符0~9 与A~F(必须是大写字母,小写字母用于变量名)。

类似于其他许多高级语言,完整的表达式由变量、常数和运算符等组成。不同的是,bc仅支持一种数据类型——数值。

每个表达式都具有一定的精度。表达式的精度取决于初始的常数值、变量值,以及执行的运算。合法的精度是0至C语言整型数能够表示的最大数值。

下面是bc支持的各种表达式(其中,expr是任何一种表达式,var是一个简单变量或数组变量,除非特别指定,计算结果的精度是表达式蕴含的最大精度):

- expr  表达式的值是计算结果的负值。

++ var  在变量值的基础上加1,然后再把计算结果赋予变量。表达式的值是计算后的结果。

-- var  从变量的值中减1,然后再把计算结果赋予变量。表达式的值是计算后的结果。

var ++  表达式的值是变量的当前值。然后再在变量值的基础上加1,把计算结果赋予变量。

var --  表达式的值是变量的当前值。然后再从变量的值中减1,把计算结果赋予变量。

expr1 + expr2  两个表达式的和。

expr1 - expr2  两个表达式的差。

expr1 * expr2  两个表达式的积。

expr1 / expr2  两个表达式的商。计算结果的精度是scale变量值表示的精度。

expr1 % expr2  表达式的计算结果是第一个表达式整除以第二个表达式后的余数。例如,为了计算a%b,首先计算a/b,取其整数部分。最终的计算结果等于a-(a/b)*b。

expr1 ^ expr2  表达式的计算结果是expr1expr2次方。第二个表达式expr2必须是一个整数。

( expr )  修改标准的优先顺序,强制计算圆括号内的表达式。

var = expr  把表达式的计算结果值赋予变量。

var op= expr  等价于“var = var op expr”,表示把变量的值与表达式的计算结果经过op运算后赋予变量,其中op是“+”、“-”、“*”、“/”、“%”或“^”等运算符之一。注意,bc也支持=+、=-、=*、=/、=%和=^等风格的赋值运算符。

关系表达式是一种特殊的表达式,其计算结果总是0或1。如果关系为假,计算结果就是0;如果关系为真,计算结果就是1。有效的关系运算符如下:

expr1 < expr2  如果表达式expr1小于表达式expr2,计算结果为1。

expr1 <= expr2  如果表达式expr1小于等于表达式expr2,计算结果为1。

expr1 > expr2  如果表达式expr1大于表达式expr2,计算结果为1。

expr1 >= expr2  如果表达式expr1大于等于表达式expr2,计算结果为1。

expr1 == expr2  如果表达式expr1等于表达式expr2,计算结果为1。

expr1 != expr2  如果表达式expr1不等于表达式expr2,计算结果为1。

布尔运算也是合法的。如同关系表达式,所有布尔运算的结果均为1或0,分别对应于真或假。布尔运算符如下:

! expr  如果表达式是0,计算结果为1。

expr1 && expr2  如果两个表达式均为非0,计算结果是1。

expr1 || expr2  如果任何一个表达式为非0,计算结果是1。

计算表达式的优先顺序如下(从最低到最高):

注意,在处理关系运算符、逻辑运算符和赋值运算符时,一定要注意其优先顺序,以免出现意外的结果。

作为一种特殊的表达式,bc提供一组标准的函数。可以在语句、表达式或用户定义的函数中使用。

length ( expr )  函数的值是表达式有效数字的位数。

read ( )  不管出现在何处,其功能是从标准输入读取一个数值。read函数的值是从标准输入读取的一系列数字利用ibase变量的当前值作为进位制转换后的结果。

scale ( expr )  函数的值是表达式计算结果的小数点后面数字的位数。

sqrt ( expr )  函数的值是表达式的平方根。如果表达式是一个负数,将会产生运行时错误。

语句

如同大多数代数语言一样,bc语句提供一种表达式的顺序计算方法。bc是一种解释语言,当遇到换行符,已经读取一个或多个完整的语句时,立即开始执行。在bc中,由于表达式是立即解释执行的,换行符的使用是非常重要的。如果位置不当,将会引起语法错误。事实上,分号“;”与换行符均用作语句的分隔符。下面是bc支持的各种语句,其中,statement-list是由一系列语句组成的语句组,之间加分号或换行符分隔符。方括号“[ ]”表示其中的语句部分是选用的。

expression  表达式也是一种语句,具有两个功能:如果表达式以变量名加等号开始,则按赋值语句处理;如果表达式并非赋值语句,则计算表达式并输出其结果。在输出计算结果值之后,再输出一个换行符。例如,“a=1”是赋值语句,而“(a=1)”则是一个具有内置赋值语句的表达式。输出的所有数值均按obase变量指定的进位制计算。obase变量的合法取值是2~999(BC_BASE_MAX),但通常很少使用大于16的进位制。

string  输出的字符串。字符串是从第一个双引号开始直至下一个双引号之间的所有字符。其中的所有字符,包括换行符,均按其字义处理。字符串之后也不输出换行符。

print list  print语句提供另外一种输出方法。其中的参数list是一组字符串或表达式,中间以逗号“,”为分隔符。每个字符串或表达式均按其位置顺序依次输出。最后没有换行符输出。表达式计算后即输出其结果,然后把这个数值赋予last变量。语句中的字符串直接输出,其中可以包含以反斜线为起始字符的特殊字符,bc认可的特殊字符是“\a”(警示音)、“\b”(退格符)、“\f”(换页符)、“\n”(换行符)、“\r”(回车)、“\q”(双引号)、“\t”(制表符)和“\\”(反斜线)。反斜线后的其他任何字符忽略之。

{ statement-list }  组合语句。允许把多个语句组合在一起执行。

if ( expr ) statement-list1 [else statement-list2]  if语句首先计算表达式,然后根据表达式的值决定执行statement-list1statement-list2。如果表达式的计算结果非0,则执行statement-list1。如果statement-list2存在,且表达式的计算结果为0,则执行statement-list2

while ( expr ) statement-list  while语句用于循环执行一组语句。每次在开始执行语句之前,while首先要计算表达式。如果表达式的计算结果非0,则执行语句;如果表达式的计算结果为0,或中间执行了break语句,将终止while循环。

for ( [expr1] ; [expr2] ; [expr3] ) statement-list  for语句用于控制循环执行的一组语句。在开始循环之前,首先计算表达式expr1。在每组语句之前,计算表达式expr2。如果计算结果非0,则执行循环体中的语句;如果计算结果为0,循环终止。每执行一次循环体中的语句之后,且在重新计算表达式expr2之前,计算一次表达式expr3。如果表达式expr1expr3省略,在其应该计算之处也忽略之。如果表达式expr2也省略,其默认值为1,表示无限循环。for语句可以表述为下列等价的while语句:

expr1;
while (expr2) {
        statement-list;
        expr3;
}

break  break 语句用于强制退出最近一层的while或for循环语句。

continue  continue语句用于中止最近一层for语句的当前循环,转而开始执行下一轮循环。

halt  halt语句用于退出bc。

return  从函数中返回数值0。参见下面的函数介绍。

return ( expr )  从函数中返回表达式的值。注意,圆括号并非必需的。

伪语句

伪语句并非传统意义上的语句,原则上不能执行(在交互运行环境中实际上是可以执行的)。

limits  显示当前bc版本的限制。

quit  退出并终止bc的执行。

warranty  显示软件的保修信息。

函数

函数提供了一种方法,用于实现自定义的算法,以便在以后调用。bc中的函数总是计算出一个数值并返回调用者。一个函数可以定义如下(花括号的位置是任意的):

define name ( parameters ) { statement-list; }

define name ( parameters ) {
        auto-list;
        statement-list; }

调用函数时只需给出“name(parameters)”形式的表达式即可。其中的参数可以是零个、一个或一组数值(或数组)。在函数定义中需要列出形式参数的名字,多个参数中间需加逗号分隔符。所有的参数都是数值参数,按值调用。如果参数是数组,可以使用“name[]”形式表示。数组也是按值调用的。

在调用函数时,实际参数是一个数字表达式。如果实际参数是一个数组,调用时应采用与形式参数相同的表达方式。由于函数的定义是动态的,仅当调用函数时才检测参数的数量与类型。不管是数量还是类型,任何不匹配都会引起运行时错误。调用未定义的函数也会导致运行时错误。

auto-list是一组选用的变量,仅限于函数“本地”使用。如果存在,auto-list的语法格式具有“auto name, ... ;”形式,其中每个name是变量的名字,分号是选用的。数组的名字可与数组参数同名。auto变量不同于传统的本地变量,当函数a调用函数b时,函数b可以使用相同的名字,直接访问函数a中的auto变量,除非函数b定义了同名的auto变量。由于auto变量和参数在调用时即置于栈中,故bc支持递归的函数调用。

statement-list是函数体中的一系列bc语句。同样,语句之间需加分号或换行符分隔符。return语句引起函数的终止执行,同时返回一个数值。return语句具有两种形式:“return ( expression )”表示计算表达式的值,然后返回其计算结果。return是“return (0)”的缩写形式,仅返回一个数值0。如果省略了return语句,蕴含着函数体最后存在一个“return (0)”语句。

在函数中,可以重新定义ibase变量。在调用函数时,函数体中的所有常数均按新的ibase变量值进行转换。但是,如果函数中用到标准函数read,read函数总是以函数外部ibase变量的当前值为准,不受函数中ibase变量的影响。下面是一个采用递归方式求取阶乘的函数。

define f (x) {
        if (x <= 1) return (1);
        return (f(x-1) * x);
}

函数也可以定义为void类型,void类型的函数不返回任何数值,因而不能用于需要数值的位置。关键字void位于关键字define与函数名之间。

数学库函数

如果运行bc时指定了“-l”选项,将会预先加载一个标准数学库函数。数学库函数将按照调用函数时已设定的精度输出计算结果,默认的精度(scale)是20。数学库函数定义了下列函数:

s (x)  求取x的正弦值,x的单位是弧度。

c (x)  求取x的余弦值,x的单位是弧度。

a (x)  求取x的余切值,x的单位是弧度。

l (x)  求取x的自然对数。

e (x)  求取e的x次方。

j (n,x)  贝塞尔(Bessel)函数。其中,n为函数的阶数,x为函数的自变量。

应用实例

1. 采用交互方式直接运行bc,计算各种表达式。

$ bc
100+100
200
quit
$

2. 使用标准的数学库函数进行计算。

$ bc -l
e(2)
7.38905609893065022723
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