Linux计算器bc学习

    • 基本使用
    • 内置变量
      • 使用内置变量进行进制转换
    • 变量
    • 运算以及内置函数
    • 语言语法
      • 关键字
      • 函数
      • 操作
    • 程序选项
    • 示例
      • 示例一指定PI的值
      • 示例二指数函数的实现
      • 示例三一个银行问题的解决

Linux内的bc计算器是一个非常强大的计算器,内置了一套类似C语言的语法。学习bc可以不用高级编程语言的情况下解决一系列的问题。但是目前网上没有找到很好的中文教程,在此自己写一个,方便以后查阅。

基本使用

最基本的是日常使用的计算,这样子和Windows自带的计算器没有太大的差别,不过一目了然的输入和运算优先级的支持还是要强大很多。具体方法如下:

bc
1+2*3-5*2
-3

注:上述示例意为输入bc后启动,输入1+2*3-5*2后按回车,得到结果-3

内置变量

但是在输入5/4的时候,会得到1。这是因为bc有若干内置变量,其中的scale内置变量指定运算要用到的小数点后的位数,默认为0,即只支持指定运算。因此,在运算前设置scale=2,就会得到正确的结果啦!^_^

总共有4个内置变量,为:

变量名称 作用
scale 指定运算要用到的小数点后的位数
ibase 指定输入的进制数
obase 指定输出的进制数
last或者. 最近打印的数字(扩展)

使用内置变量进行进制转换

指定输入输出进制的情况下就能轻松处理进制转换了!比如二进制转16进制:

ibase=2
obase=16
1010
101

这是怎么回事?不是应该是A吗?原因在于:先指定了二进制的输入,在指定obase变量的时候,16也被认为是二进制的输入啦!在二进制的输入情况下,所有的非0全部认为是1,于是16被看作是11,即3进制。1010对应十进制是10,101对于的3进制也是10。就是这样啦。

正确的方法应该是先指定obase,如下:

obase=16
ibase=2
1010
A

变量

bc可以支持用户自定义变量。变量有2种类型,数字和数组。注意,不支持字符串类型的变量,数组也只能是数字的数组。至于变量的赋值,和C语言语法一致:

var_name = 123;
array_name[13] = 2;

在以上的例子中,声明了一个var_name的变量,赋值为123。声明了一个名为array_name的数组,它的0到12号元素均为0,13号元素为2。注意,分号可有可无,但是如果是写脚本程序的话,写上为好。

所有的变量在未赋值时均为0。

如果在变量前面加入auto,则表明是局部变量,否则为全局变量。(函数的参数为局部变量,是例外情况)

运算以及内置函数

bc支持以下几种运算:

运算符 解释
++,– 同C语言,也分前置和后置
+,-,*,/ 同C语言
+=,-=,*=,/= 同C语言
%,%= 取余。当scale=0时同C语言,否则见下
^ 指数运算(只支持整数的指数)
<,<=,>,>=,==,!= 同C语言
!, &&, || 同C语言

注意取余运算,当scale不为0时,如,scale=2,则:
4 % 3 = 0.01
这是由于4/3=1.33,4-3*1.33=0.01

另外,bc还有4个内置函数,分别是:

名称 作用
length 得到一个变量的有效数字个数
read 得到用户输入
scale 不同于内置变量,这个内置函数意为得到变量小数点后的数字的个数
sqrt 开方运算

具体示例参见后面的程序。

语言语法

主要的语法完全可以参照C语言。注意的是:当一个值没有被赋予变量时,会直接输出,因此可以通过直接输入字符串的方式得到输出。字符串以""包裹。

关键字

有以下的关键字:

关键字 作用
print 输出变量,后面是一个列表,以,分隔,会将其依次输出,注意,不会输出换行符,需要自己添加”\n”。关于转义字符,和C语言相同。
{} 大括号构成语言块,作用和C语言相同
if,else 用法和C语言相同
for 和C语言相同
break 和C语言相同
continue 和C语言相同
while 和C语言相同
return 和C语言相同
halt 当运行到此语句时,程序退出

函数

函数的声明方法:

define function_name(var_list) {
    function_body;
}

如:

/*递归版本的阶乘函数*/
define factorial(x) {
    if (x <= 1)
        return 1;
    return x * factorial(x-1);
}
factorial(5)
120

当函数无返回值时,执行会有问题。此时需要在define和函数名之间加入void关键字。为:

define func_a() {
    print "this is func a\n";
}
define void func_b() {
    print "this is func b\n";
}
func_a();
this is func_a
0
func_b();
this is func_b

操作

有以下的操作符:

名称 内容
limits 输入后会得到本版本bc的各个最大值
quit 退出程序
warranty 得到一个更多的版本信息

程序选项

选项内容如下:

内容 作用
-l 提前加载数学库,并将scale设置为20
-q 安静模式,不输出欢迎信息
-v 输出版本信息
-s 使用POSIX标准bc语言,而非GNU扩展语言

数学函数库中,有以下几个常用函数:

函数名 内容
s(x) sin函数
c(x) cos函数
a(x) atan函数
l(x) ln函数
e(x) e的x次幂
j(n, x) x的n阶贝塞尔函数,(n为整数)

示例

示例一:指定PI的值

bash中可以使用以下方法指定 π 的值给环境变量:
pi=${echo "scale=10;4*a(1)" | bc -l}

示例二:指数函数的实现

以下是man手册中,实现的e(x)的函数。没有使用GNU扩展语法,使用的是POSIX的标准bc语法。思路是由公式:

ex=(ex2)2

得以使x一直除以2而变小,当x小到一定程序时,可以利用泰勒展开:
ex=1+x+x22!+x33!+

来计算了。
程序如下:

scale = 20
define e(x) {
    auto a, d, e, f, i, m, v, z

    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
    }
}

其中,v/1可能看着有些奇怪。这是将变量截取到当前的scale。比如:

scale=5
a=0.123456789
a
.123456789
a /= 1
a
.12345

示例三、一个银行问题的解决

问题如下:

假设一年以后开始存养老金,每年将工资的2%存入银行帐户,年利率8%,去年的工资为50000元,并且每年4%速度增长。假如你40年后退休,到那时一共存了多少钱?

可以写一个如下的脚本:

#!/usr/bin/bc -q
scale = 10

salary = 50000;
save = 0.02;
increase = 0.04;
interest = 0.08;
sum_save = 0;

print "Please input num of years: ";
year = read();

for (i = 0; i < year; i++) {
    sum_save += salary * save;
    sum_save *= 1 + interest;
    salary *= 1 + increase;
}

scale = 2;
sum_save /= 1;
print "After ", year, " years, you save money ", sum_save, "\n"

运行结果为:
Please input num of years:40
After 40 years, you save money 456934.52

总体来说,仅仅使用bc就可以解决一系列的计算问题啦!

你可能感兴趣的:(linux,命令,语言,教程,bc)