命令行计算器概览
当需要做点数值计算时,当然可以用很多种编程语言。但有时我们只想方便一点,于是unix下有一些小计算器。
expr
expr的用法很简单:
expr 表达式
另外,shell命令中也可用$((表达式))
,它会被替换为结果。
expr支持下列运算,按优先级递增为:
运算 | 值 |
---|---|
ARG1 &124; ARG2 | ARG1非零非null时ARG1,否则ARG2 |
ARG1 & ARG2 | 两个参数都非零非null时ARG1,否则0 |
ARG1 < ARG2 | 小于 |
ARG1 <= ARG2 | 小于等于 |
ARG1 = ARG2 | 等于 |
ARG1 != ARG2 | 不等 |
ARG1 >= ARG2 | 大于等于 |
ARG1 > ARG2 | 大于 |
ARG1 + ARG2 | 加法 |
ARG1 - ARG2 | 减法 |
ARG1 * ARG2 | 乘法 |
ARG1 / ARG2 | 除法 |
ARG1 % ARG2 | 求余 |
STRING : REGEXP | STRING是否匹配REGEXP,有(时返回(与)间匹配部分或null,否则返回匹配的字符数 |
match STRING REGEXP | 相当于 STRING : REGEXP |
substr STRING POS LENGTH | STRING由POS(由1开始)的子字符串 |
length STRING | STRING的长度 |
+ TOKEN | 把TOKEN视为字符串,即使它是运算符 |
( EXPRESSION ) | EXPRESSION的值 |
其中仅当参数都为数值时比较为数值比较,否则为字符串比较。
expr在结果非零非null时返回0,否则返回1。语法错误返回2,其它错误返回3。
dc
dc是桌面计算器(desk calculator)的缩写,它处理后缀表达式(也称逆波兰式),可以完成任意精度的定点(而非浮点)运算,甚至使用宏。
后缀表达式的优点在于计算机容易解读和处理,还省去优先级问题。可惜大家习惯了糟糕的中缀表达式,所以反而觉得dc奇特。
dc显然用栈架构实现,打开dc后每输入一个数值(整数或小数,但不支持指数),就被压入栈中,两个相邻数值用空格或换行分隔。每输入一个被方括号包围的字符串也会被压入栈中。当碰到以下的命令,会作相应操作。
打印命令 | 用途 |
---|---|
p | 打印栈顶再换行 |
n | 打印并弹出栈顶 |
P | 弹出栈顶,字符串的话打印之,否则绝对值的整数部分以字节序列形式打印 |
f | 打印栈 |
算术命令 | 用途 |
---|---|
+ | 弹出两个元素并推入它们之和 |
- | 弹出两个元素并推入它们之差 |
* | 弹出两个元素并推入它们之积 |
/ | 弹出两个元素并推入它们之商(先弹出的为除数) |
% | 弹出两个元素并推入它们之余(先弹出的为除数) |
~ | 弹出两个元素并推入它们之商和余(先弹出的为除数) |
^ | 弹出两个元素并推入它们之幂(先弹出的为被指数) |
| | 幂模(先弹出模、再弹出指数、然后底) |
v | 弹出栈顶并推入其平方根 |
栈控制命令 | 用途 |
---|---|
c | 清空栈 |
d | 重复压入栈顶 |
r | 交换栈顶和栈顶下面的一个元素 |
dc提供至少256个内存寄存器,分别以单个字符命名,每个寄存器都是栈。
寄存器命令 | 用途 |
---|---|
sr | 弹出栈顶并把它压入寄存器r |
lr | 把寄存器r的栈顶推入主栈 |
Sr | 弹出栈顶并把它压入寄存器r |
Lr | 弹出寄存器r的栈顶推入主栈 |
进制可以从2到16。精度为非负整数,表示保留的小数位个数,默认0即除加减法外结果为整数。
参数命令 | 用途 |
---|---|
i | 弹出栈顶用作输入进制 |
o | 弹出栈顶用作输出进制 |
k | 弹出栈顶用作精度 |
I | 把当前输入进制推入栈 |
O | 把当前输出进制推入栈 |
K | 把当前精度推入栈 |
字符串命令 | 用途 |
---|---|
a | 弹出栈顶,若为数值则把其最低字节转换为字符串推入栈,否则推入首个字符 |
x | 弹出栈顶并作为宏执行之 |
>r | 若先弹出的大于接着弹出的,则执行寄存器r的内容 |
!>r | 若先弹出的不大于接着弹出的,则执行寄存器r的内容 |
<r | 若先弹出的小于接着弹出的,则执行寄存器r的内容 |
!<r | 若先弹出的不小于接着弹出的,则执行寄存器r的内容 |
=r | 若先弹出的等于接着弹出的,则执行寄存器r的内容 |
!=r | 若先弹出的不等于接着弹出的,则执行寄存器r的内容 |
? | 从终端读一行并执行之 |
q | 退出宏和,调用它的宏。如果没有宏在执行,退出dc |
Q | 弹出栈顶并退出那么多层宏执行 |
状态查询命令 | 用途 |
---|---|
Z | 弹出栈顶并推入其不含前导零的位个数(字符串为字符数) |
X | 弹出栈顶并推入其小数位个数(字符串为0) |
z | 推入当前栈深 |
杂项命令 | 用途 |
---|---|
! | 把本行余下部分看作系统命令,以 <、 =或>开始的命令名前加空格 |
# | 把本行余下部分看作注释 |
:r | 把数组r的下标为先弹出者的元素设为接着弹出的 |
;r | 弹出栈顶并把数组r以它为下标的元素压入栈 |
和unix其它小语言一样,紧凑有时导致难读,dc有一个非常著名的例子,是一个用Perl实现的RSA公共密钥算法,广泛发布在签名档和T恤上,以示对美国1995年的限制密码学出口的抗议。
print pack"C*",split/D+/,`echo"16iII*oU@{$/=$z;[(pop,pop,unpack "H*",<>)]}EsMsKsN0[1N*11K[d2%Sa2/d0<x+d*lmLa^*1N%0]dsXx++1M1N/dsM0<J]dsJxp"|dc`
bc
bc则处理中缀表达式,可以完成任意精度的定点(而非浮点)运算,并有d类似C语言的控制结构。但很多方面都可看出其设计不完善。
bc可用/和/包围注释,或者用#开始行末注释。bc用换行或分号分隔语句。不完整语句会导致自动续行,也可用反斜杠续行。
常量和变量
bc中数值常量可有小数点,数值可以有任意精度,内部用十进制表示。
bc中字符串常量用被双引号包围的字符串表示,可用类似C的转义序列。
bc中变量名从小写字母开始,后接若干小写字母、数字或下划线。变量同时可作一维数组变量(保存一些以数值(可以不是整数)为下标索引的数值,用方括号指定下标)和简单变量(保存一个数)。未赋值的变量的值为0。
特殊变量 | 用途 |
---|---|
scale | 运算中保留的小数位数 |
ibase | 输入进制,默认10 |
obase | 输出进制,默认10 |
last | 保存上次打印的数 |
表达式
和C语言类似,表达式由常量的变量经运算符、括号和函数调用(形如函数名(参数列表)
,其中数组变量后缀[]
)组合而成。
运算符优先级从高到低为:
- 不结合:++ var、– var、var ++、var –
- 不结合:- expr
- 右结合:expr ^ expr
- 左结合:expr * expr、 expr / expr、 expr % expr
- 左结合:expr + expr、 expr - expr
- 右结合:var = expr、 var
= expr - 左结合:expr1 < expr2、 expr1 <= expr2、 expr1 > expr2、 expr1 >= expr2、 expr1 == expr2、 expr1 != expr2
- 不结合:!expr
- 左结合:expr && expr
-
左结合:expr expr
注意这顺序与C语言不同,如a = 3 < 5
会把变量a设为3而非1。另外,数值运算以十进制进行。
标准的函数有:
表达式 | 值 |
---|---|
length(表达式) | 有效位数(小数点后的都视为有效),如length(.000001)为6,length(1935.000)=7 |
read() | 从标准输入读的一个数(小心与代码混淆),如length(.000001)为6,length(1935.000)=3 |
scale(表达式) | 小数点后位数 |
sqrt(表达式) | 平方根 |
启用-l选项的话还可用以下数学函数:
表达式 | 值 |
---|---|
s(x) | x的正弦 |
c(x) | x的余弦 |
a(x) | x的反正切 |
l(x) | x的自然对数 |
e(x) | $e^x $ |
j(n,x) | x的n阶Bessel函数值 |
语句
语句 | 用途 | |
---|---|---|
表达式 | 求值表达式,非赋值表达式会打印结果 | |
常量 | 打印它 | |
print 逗号分隔的表达式或字符串列表 | 打印各值 | |
{ 语句序列 } | 复合语句 | |
if ( expression ) statement1 [else statement2] | 与C类似 | |
while ( expression ) statement | 与C类似 | |
for ( [expression1] ; [expression2] ; [expression3] ) statement | 与C类似 | |
break | 与C类似 | |
continue | 与C类似 | |
halt | 退出bc | |
return | 返回0 | |
return 表达式 | 与C类似 |
另外,在编译时碰到quit语句会退出bc,碰到limits会输出实现限制。
函数定义形如
define 名称 ( 参数列表 ) {
局部变量列表
一系列语句
}
其中,参数列表中零个或多个名字由逗号分隔(数组要加后缀[]
),参数一般按值传递(除非数组参数加前缀*
)。
可选的局部变量列表形如auto 名字,...;
,分号也是可选的。由于bc用简单的栈结构实现局部变量,当函数a调用b时,b可以访问a的局部变量。
函数体中常量按调用时的ibase解读。不指定返回值将返回0。