在类似Unix的操作系统上,bc是用于执行任意精度数学计算的语言,并且是该语言的交互式解释器。
查看英文版
1 bc 运行系统环境
2 bc 说明
3 bc 语法
4 bc 例子
Linux
bc是一种支持任意精度数字的语言,这意味着无论数字有多大(或非常小),它都能提供准确的结果。
它具有交互模式,可以接受来自终端的输入并根据要求提供计算。作为一种语言,它的语法类似于C编程语言。使用命令行选项可以使用标准数学库。如果需要,则在处理任何文件之前先定义数学库。
bc首先以列出的顺序处理命令行中列出的所有文件中的代码。处理完所有文件后,bc从标准输入读取。所有代码都在读取时执行。
较新的bc版本包含了对传统bc实现和POSIX草案标准的扩展。命令行选项可能导致这些扩展名打印警告或被拒绝。本文档介绍了bc语言的较新版本。如果特定功能是标准的扩展,则在下面相应说明。
查看英文版
bc [ -hlwsqv ] [long-options] [ file ... ]
-h, --help |
打印帮助信息并退出。 |
-i, --interactive |
强制交互模式。 |
-l, --mathlib |
定义标准数学库。 |
-w, --warn |
对POSIX bc的扩展名发出警告。 |
-s, --standard |
精确处理POSIX bc语言。 |
-q, --quiet |
不要打印普通的GNU bc欢迎消息。 |
-v, --version |
打印版本号和版权信息,然后退出。 |
bc中最基本的元素是数字。数字是任意精度的数字。此精度在整数部分和小数部分中都存在。所有数字内部均以十进制表示,所有计算均以十进制表示。某些版本的bc 截断是除法和乘法运算的结果。
数字有两个属性,长度和小数位数。长度是数字中有效十进制数字的总数,小数位数是小数点后的十进制数字的总数。例如:
.000001 的长度为6,小数位数为6。
1935.000 的长度为7,小数位数为3。
数字存储在两种类型的变量中:简单变量和数组。简单变量和数组变量都被命名。名称以字母开头,后跟任意数量的字母,数字和下划线。所有字母必须为小写。全字母数字名称是扩展名。在POSIX bc中,所有名称均为单个小写字母。变量的类型在上下文中是清楚的,因为所有数组变量名都将后跟方括号([])。 Full alphanumeric names are an extension. In POSIX bc all names are a single lower case letter. The type of variable is clear by the context because all array variable names will be followed by brackets ([]).
有四个特殊变量:scale,ibase,obase和last。
标度定义某些操作如何使用小数点后的数字。scale的默认值为0。
ibase和obase定义输入和输出数字的转换基础。输入和输出的默认值为10。
last(扩展名)是一个具有最后打印数字的值的变量。
所有变量都可以分配有值,并且可以在表达式中使用。
评论在公元前开始以字符“ / * ”和结束与字符“ * / ”。注释可以在任何地方开始,并在输入中显示为单个空格。这将导致注释分隔其他输入项。例如,注释不能放在变量名的中间。注释包括注释开头和结尾之间的任何换行符(行尾)。
为了支持对bc使用脚本,已添加一行注释作为扩展名。单行注释以“ # ”字符开头,并继续到下一行。行尾字符不是注释的一部分,可以正常处理。
数字由表达式和语句操纵。由于该语言被设计为交互式的,因此语句和表达式将尽快执行。没有“主”程序;而是在遇到代码时执行代码。遇到功能时,将定义后面将详细讨论的功能。
一个简单的表达式只是一个常数。bc使用变量ibase指定的当前输入基数将常量转换为内部十进制数。函数中有一个例外。的合法值IBASE是2至16。将超出此范围的值分配给ibase将得到2或16的值。输入数字可能包含字符0-9和AF。注意:它们必须是大写字母。小写字母保留用于变量名。不管ibase的值如何,一位数字始终具有该数字的值。对于多位数,bc将所有大于或等于ibase的输入数字更改为ibase-1的值。这使得数字FFF始终是输入基数的最大3位数字。
完整表达式类似于其他高级语言。由于只有一种数字,因此没有混合变量类型的规则。取而代之的是在表达式范围内有规则。每个表达式都有一个比例,该比例是从原始数字的比例,执行的操作以及在许多情况下可变scale的值得出的。可变标度的合法值是0到C整数可表示的最大值。
在以下对合法表达式的描述中,“ expr ”是指完整表达式,而“ var ”是指简单变量或数组变量。一个简单的变量只是一个名称,而一个数组变量被指定为名称 [ expr ]。
除非特别说明,结果的标度是所涉及表达式的最大标度。
- expr - 结果是表达的否定。
++ var - 变量加1,新值是表达式的结果。
-- var - 变量被减一,新值是表达式的结果。
var ++ - 表达式的结果是变量的值,然后变量加1。
var -- - 表达的结果是该变量的值,然后该变量被减一。
expr + expr - 表达式的结果是两个表达式的总和。
expr - expr - 表达式的结果是两个表达式的差。
expr * expr - 表达式的结果是两个表达式的乘积。
expr / expr - 表达式的结果是两个表达式的商。结果的标度是可变标度的值。
expr % expr - 表达式的结果为“余数”,它的计算方式如下。为了计算一%b,第一一/ b被计算为比例位数。该结果被用来计算一个- (一/ b )* b的最大的规模规模+ 比例(b )和刻度(一)。如果将scale设置为零,并且两个表达式均为整数,则此表达式为整数余数函数。
expr ^ expr - 表达式的结果是第一个的值提高为第二个的幂。第二个表达式必须是整数。如果第二个表达式不是整数,则会生成警告,并且该表达式将被截断以获得整数值。如果指数为负,则结果的小数位数为小数位数。如果指数为正,则结果的标度是第一个表达式的标度的最小值乘以指数的值以及最大的标度和第一个表达式的标度。(例如scale(a ^ b )= min(scale (a )* b ,max( scale , scale (a )))。)应该注意,expr ^ 0将始终返回值1。
( expr ) - 这会更改标准优先级以强制对表达式进行求值。
var = expr - 为变量分配表达式的值。
var = expr - 此表达式等效于“ var = varexpr ”,不同之处在于“ var ”部分仅被评估一次。如果“ var ”是一个数组,这可以有所作为。
关系表达式是一种特殊的表达始终评估为0或1:0,如果关系是假的,1,如果关系是真实的。这些可能以任何法律表达形式出现。POSIX bc要求仅在if,while和for语句中使用关系表达式,并且只能在其中进行一个关系测试。关系运算符是:
expr1 < expr2 |
如果expr1严格小于expr2,则结果为1 。 |
expr1 <= expr2 |
其结果是1,如果expr1的是小于或等于表达式2。 |
expr1 > expr2 |
如果expr1严格大于expr2,则结果为1 。 |
expr1 >= expr2 |
其结果是1,如果表达式1大于或等于表达式2。 |
expr1 == expr2 |
如果expr1等于expr2,则结果为1 。 |
expr1 != expr2 |
如果expr1不等于expr2,则结果为1 。 |
布尔运算也是合法的。(POSIX bc没有布尔操作)。与关系表达式中一样,所有布尔运算的结果均为0和1(对于false和true)。布尔运算符为:
!expr |
如果expr为0,则结果为1 。 |
expr && expr |
如果两个表达式都不为零,则结果为1。 |
expr || expr |
如果两个表达式都不为零,则结果为1。 |
表达式优先级如下:(从最低到最高)
选择该优先级是为了使符合POSIX的bc程序能够正确运行。与赋值表达式一起使用时,这将导致关系和逻辑运算符的使用具有某些异常行为。考虑以下表达式:
a = 3 < 5
大多数C程序员会假设这会将结果“ 3 <5 ”(值1)分配给变量“ a ”。这在bc中的作用是将值3分配给变量“ a ”,然后将3与5进行比较。将关系运算符和逻辑运算符与赋值运算符一起使用时,最好使用括号。
bc中提供了一些其他特殊表达式。这些与用户定义的功能和标准功能有关。它们都显示为“ 名称(参数) ”。有关用户定义的功能,请参见功能部分。标准功能是:
长度( 表达式 )
长度函数的值是表达式中的有效位数。
阅读()
读取功能(扩展)将从标准输入读取的数,而不管其中函数发生的。请注意,这可能会导致标准输入中数据和程序混合的问题。此功能的最佳用途是在先前编写的程序中,需要用户输入,但绝不允许用户输入程序代码。读取功能的值是使用转换基础的变量ibase的当前值从标准输入读取的数字。
规模( 表示 )
标度函数的值是表达式中小数点后的位数。
sqrt( 表达式 )
sqrt函数的值是表达式的平方根。如果表达式为负,则会生成运行时错误。
语句(与大多数代数语言一样)提供了表达评估的顺序。在bc中,语句“尽快”执行。当遇到换行符并且存在一个或多个完整语句时,将执行执行。由于立即执行,换行符在bc中很重要。实际上,分号和换行符都用作语句分隔符。换行符放置不当会导致语法错误。因为换行符是语句分隔符,所以可以使用反斜杠字符来隐藏换行符。序列“ \”(其中是换行符)在bc中显示为空白而不是换行符。语句列表是一系列由分号和换行符分隔的语句。以下是bc语句及其作用的列表:方括号([])中的内容是语句的可选部分。
表达 |
该语句执行以下两项操作之一。如果表达式以“... ” 开头,则将其视为分配语句。如果该表达式不是赋值语句,则对该表达式求值并打印到输出。号码打印后,将换行。例如,“ a = 1 ”是赋值语句,“ (a = 1) ”是具有嵌入式赋值的表达式。所有打印的数字均以变量obase指定的基数打印。obase的合法值为2到BC_BASE_MAX。(请参阅“限制”一节。)对于2到16的基数,使用通常的数字写方法。使用多字符数字方法来打印数字,其中每个较高的基数都将作为基数10打印。多字符数字用空格分隔。每个数字包含表示“ obase-1 ”的十进制值所需的字符数。由于数字具有任意精度,因此某些数字可能无法在单个输出行上打印。这些长数字将使用“ \ ”作为一行的最后一个字符而被分成几行。每行打印的最大字符数为70。由于bc的交互性质,打印数字会导致最后将打印值分配给特殊变量的副作用。此功能使用户可以恢复打印的最后一个值,而不必重新键入打印数字的表达式。分配给最后一个是合法的,并且将使用分配的值覆盖最后打印的值。新分配的值将一直保留到下一个数字被打印或最后一个值被分配为止。某些安装可能允许使用单个句点(。)作为数字的缩写形式,而不是数字的一部分。 |
串 |
该字符串将打印到输出中。字符串以双引号字符开头,并包含所有字符,直到下一个双引号字符为止。所有字符均按字面意义使用,包括任何换行符。字符串后不打印换行符。 |
打印 清单 |
打印语句(扩展)提供输出的另一方法。“列表”是由逗号分隔的字符串和表达式的列表。每个字符串或表达式都按照列表的顺序打印。没有终止换行符被打印。计算表达式并打印其值,最后将其分配给变量。打印语句中的字符串将打印到输出中,并且可以包含特殊字符。特殊字符以反斜杠字符(\)开头。bc识别的特殊字符是“ a ”(警报或铃声),“ b ”(退格键),“ f ”(换页),“ n ”(换行符),“ r ”“(双引号),“ t ”(制表符)和“ \ ”(反斜杠)。反斜杠后面的任何其他字符将被忽略。 |
{statement_list} |
此选项是复合语句。它允许将多个语句组合在一起执行。 |
if (expression)statement1 [elsestatement2] |
如果语句计算表达式并执行语句1或语句2取决于表达式的值。如果表达式非零,则执行statement1。如果存在statement2并且表达式的值为0,则执行statement2。在其他子句是一个扩展。 |
while( 表达式 ) 语句 |
同时表达为非零语句将执行该语句。它在每次执行该语句之前对表达式求值。循环的终止是由零表达式值或执行break语句引起的。 |
for ( [expression1] ; [expression2] ; [expression3] )statement |
在对语句控制重复语句的执行。在循环之前对Expression1求值。在每次执行该语句之前对Expression2进行求值。如果非零,则对语句进行评估。如果为零,则终止循环。在每次执行该语句之后,在重新计算expression2之前先对expression3进行评估。如果缺少expression1或expression3,则在将要评估它们时将不评估任何内容。如果缺少expression2,则与将值1替换为expression2相同。。可选表达式是扩展。POSIX bc需要所有三个表达式。以下是for语句的等效代码: expression1; while (expression2) { statement; expression3; } |
打破 |
该语句导致最近的while语句或for语句的强制退出。 |
继续 |
在继续语句(扩展)导致最近的封闭for语句开始下一次迭代。 |
停止 |
停止声明(扩展),是一个执行的语句引起BC被执行时,它向处理器仅退出。例如,“ if(0 == 1)halt ”将不会导致bc终止,因为未执行暂停。 |
返回 |
从函数返回值0。(请参阅有关功能的部分。) |
返回( 表达式 ) |
从函数返回表达式的值。(请参见函数部分。)作为扩展,不需要括号。 |
这些陈述不是传统意义上的陈述。它们不是已执行的语句。它们的功能在“编译”时执行。
极限 |
打印由本地版本bc强制执行的本地限制。(这是一个扩展。) |
退出 |
当退出读声明时,卑诗处理器被终止,无论在哪里退出声明中找到。例如,“ if(0 == 1)quit ”将导致bc终止。 |
保证 |
打印保修通知。(这是一个扩展。) |
函数提供了一种定义可以稍后执行的计算的方法。bc中的函数总是计算值并将其返回给调用方。函数定义是“动态的”,即直到在输入中遇到定义之前才定义函数。然后使用该定义,直到遇到另一个具有相同名称的定义函数。然后,新定义将替换旧定义。函数定义如下:
define name ( parameters ) { newline auto_list statement_list }
函数调用只是形式为“名称(参数)”的表达式。
参数是数字或数组(扩展名)。在函数定义中,零个或多个参数通过列出用逗号分隔的名称来定义。所有参数均按值参数调用。数组在参数定义中用符号“ name [] ”指定。在函数调用中,实际参数是数字参数的完整表达式。传递数组和定义数组参数使用相同的符号。命名数组按值传递给函数。由于函数定义是动态的,因此在调用函数时会检查参数编号和类型。参数数量或类型的任何不匹配都将导致运行时错误。调用未定义函数也会发生运行时错误。
该AUTO_LIST是那些对“本地”使用变量的可选列表。自动列表的语法(如果存在)为“ 自动名称,...; ”。分号是可选的。每个名字是自动变量的名称。可以使用与参数中相同的符号来指定数组。这些变量的值在函数开始时被压入堆栈。然后将变量初始化为零,并在整个函数执行过程中使用它们。在函数退出时,将弹出这些变量,以便恢复这些变量的原始值(在函数调用时)。参数实际上是自动变量,它们被初始化为函数调用中提供的值。自动变量与传统的局部变量不同,因为如果函数A调用函数B,则B可以仅使用相同的名称访问函数A的自动变量,除非函数B称它们为自动变量。因为该自动变量和参数被压入堆栈,所以bc支持递归函数。
函数主体是bc语句的列表。同样,语句之间用分号或换行符分隔。Return语句导致函数终止并返回值。return语句有两种版本。第一种形式“ return ”将值0返回给调用表达式。第二种形式“ return(expression) ”,计算表达式的值,并将该值返回给调用表达式。每个函数的末尾都有一个隐含的“ return(0) ”,它允许函数终止并返回0,而无需显式的return语句。
函数还更改变量ibase的用法。函数主体中的所有常量将在函数调用时使用ibase的值进行转换。在执行函数期间,ibase的更改将被忽略,但标准函数读取除外,它将始终使用ibase的当前值进行数字转换。
一些扩展已添加到功能。首先,定义的格式已经稍微放松了。该标准要求开括号与define关键字位于同一行,而所有其他部分必须位于以下行。较新版本的bc允许在函数的大括号之前和之后的任意数量的换行符。例如,以下定义是合法的。
define d (n) { return (2*n); } define d (n) { return (2*n); }
函数可以定义为void。void函数不返回任何值,因此可能无法在需要该值的任何地方使用。当在输入线上被自己调用时,void函数不会产生任何输出。关键字void放置在关键字定义和功能名称之间。例如,考虑以下会话。
define py (y) { print "--->", y, "<---", "0; } define void px (x) { print "--->", x, "<---", "0; } py(1) --->1<--- 0 px(1) --->1<---
由于py不是void函数,因此对py(1)的调用将打印所需的输出,然后打印第二行,即该函数的值。由于未提供显式return语句的函数的值为零,因此将打印零。对于px(1),不会打印零,因为该函数是void函数。
此外,增加了对数组的变量调用。要通过变量array声明调用,函数定义中的array参数的声明类似于“ * name [] ”。对函数的调用与按值数组调用相同。
如果使用-l选项调用bc,则会预先加载数学库,并且默认比例设置为20。数学函数会将其结果计算为调用时设置的比例。数学库定义以下功能:
查看英文版
在sh中,以下代码将pi的值分配给shell变量pi。在这里,a表示反正切函数,它是使用-l选项加载的数学库的一部分:
pi=$(echo "scale=10; 4*a(1)" | bc -l)
以下是数学库中使用的指数函数的定义。该函数用POSIX bc编写。
scale = 20 /* Uses the fact that e^x = (e^(x/2))^2 When x is small enough, we use the series: e^x = 1 + x + x^2/2! + x^3/3! + ... */ define e(x) { auto a, d, e, f, i, m, v, z /* Check the sign of x. */ if (x<0) { m = 1 x = -x } /* Precondition x. */ z = scale; scale = 4 + z + .44*x; while (x > 1) { f += 1; x /= 2; } /* Initialize the variables. */ v = 1+x a = x d = 1 for (i=2; 1; i++) { e = (a *= x) / (d *= i) if (e == 0) { if (f>0) while (f--) v = v*v; scale = z if (m) return (1/v); return (v/1); } v += e } }
以下是使用bc的扩展功能实现用于计算支票簿余额的简单程序的代码。最好将该程序保存在文件中,以便可以多次使用它,而不必每次使用都重新键入它。
scale=2 print "\nCheck book program!\n" print " Remember, deposits are negative transactions.\n" print " Exit by a 0 transaction.\n\n" print "Initial balance? "; bal = read() bal /= 1 print "\n" while (1) { "current balance = "; bal "transaction? "; trans = read() if (trans == 0) break; bal -= trans bal /= 1 } quit
以下是递归阶乘函数的定义。
define f (x) { if (x <= 1) return (1); return (f(x-1) * x); }
查看英文版
未知的网友