我有以下 bash 脚本
# 1 + x^2/2! + x^4/4! + ... + x^(2n)/(2*n)!
#!/bin/bash
factorial() {
n=$1
fact=1
for ((i = 2; i <= $n; i++)); do
fact=$(expr $fact \* $i)
done
return $fact
}
read -p "x = " x
read -p "n = " n
sum=0
for ((i = 1; i <= n; i++)); do
val=$((2 ** ($i - 1)))
ex=$(($x ** $val))
f=$(factorial $val)
a=$(($ex / $f))
sum=$(($sum + $a))
done
echo $sum
我正在努力实现上述系列。我不需要解决方案。我只是不明白为什么会出现错误。
错误:
x = 1
n = 2
sum_of_series.sh: line 20: 1 / : syntax error: operand expected (error token is "/ ")
答案1
该错误消息是由 line 引起的,因为(除)运算符a=$(($ex / $f))
后面没有操作数。/
所以立即怀疑该变量f
是一个空字符串。
其原因是分配$( )
时命令替换的行为。f
当执行封闭的命令管道时,这会收集 stdout 的内容。由于您的factorial()
函数未向标准输出写入任何内容,因此分配给 f 的值为空。解决方案是回显或打印该值,代替return
-- 例如 as printf '%s\n' "${fact}"
。
一些可能有用的附加注释:
return 语句中的值代表函数的状态,而不是它可能生成的任何数据。在没有 return 语句的情况下,函数中执行的最后一个命令的退出状态将传递回调用者。
返回状态被截断为 8 位,并且是无符号的,因此只能取范围 0-255。
另外,外部命令的状态还有进一步的约定。由信号终止的进程的状态为 128 + 信号编号。如果 shell 无法创建新进程或执行命令,则可能会返回 126 或 127。状态 0 通常表示成功,从 1 开始的任何小整数表示命令检测到的错误或异常结果。我认为明智的做法是在 shell 函数中遵循相同的约定,并且永远不要以这种方式返回数据值。
Shell 算术(根据 GNU/bash 手册)以固定宽度整数进行计算。在我的系统上,这似乎是 64 位有符号整数,但它可能因系统和发行版而异。 31 位只能容纳 12!,63 位只能容纳 20!,这可能会限制您的范围。
该片段显示 Bash 算术溢出 63 位,大约在 9.22e+18 左右。
Paul--) for k in {1..10}; do
> printf '%s %s\n' $k $(( 3000000000000000000 * k ))
> done
1 3000000000000000000
2 6000000000000000000
3 9000000000000000000
4 -6446744073709551616
5 -3446744073709551616
6 -446744073709551616
7 2553255926290448384
8 5553255926290448384
9 8553255926290448384
10 -6893488147419103232
Paul--)
对于大数字,我的首选是 dc 命令,它可以不受限制的数字大小,但需要 RPN(反向波兰表示法)。该片段生成 RPN 命令来列出最多 10 的阶乘!
Paul--) { echo 1; seq -s ' p * p ' 2 10; echo ' p * p q'; }
1
2 p * p 3 p * p 4 p * p 5 p * p 6 p * p 7 p * p 8 p * p 9 p * p 10
p * p q
Paul--)
这是执行(但我测试了最多 400 个!):
Paul--) { echo 1; seq -s ' p * p ' 2 10; echo ' p * p q'; } | dc
2
2
3
6
4
24
5
120
6
720
7
5040
8
40320
9
362880
10
3628800
Paul--)