bash 中的浮点数

bash 中的浮点数

假设我有一个变量,我想在将其乘以 1000 后打印 5 位有效数字。zsh可以这样做:

zsh$ x=2.8026407e+00
zsh$ printf "%.5g\n" "$(( 1000*${x} ))"
zsh> 2802.6

也能bash做到吗?

bash$ x=2.8026407e+00
bash$ printf "%.5g\n" "$(( 1000*${x} ))"
bash> bash: 1000*2.8026407e+00 : syntax error: invalid arithmetic operator (error token is ".8026407e+00 ")

我认为没有办法让原生 bash 理解浮点运算,是吗?我知道我可以使用 eg awk,但我想知道是否bash可以这样做。

(我并不惊讶bash不能处理浮动,但zsh可以!)

答案1

bash不进行浮点运算,而是进行定点运算,其中小数点固定在零位(即整数数学)。这意味着你围绕它进行一些非常非常基本的计算:

$ a=1;b=3
$ echo $(( (a*1000 / b ) ))
333

因此,1/3 到三位数是 0.333。

这是一个坏主意;不要这样做。

在命令行上进行 FP 数学计算的方法有很多种。这里仅举两个例子:

$ python -c 'print( 1.0 / 3 )'
0.333333333333
$ echo 'scale=3; 1.0/3' | bc
.333

答案2

bash不能进行小数点数学运算,只能进行整数运算

robert@pip2:/tmp$ echo $((2 * 3))
6
robert@pip2:/tmp$ echo $((2 * 3.5))
bash: 2 * 3.5: syntax error: invalid arithmetic operator (error token is ".5")
robert@pip2:/tmp$ 

答案3

是的,像 dash 一样,bash 仅限于$((…)).
事实上,默认情况下,所有 shell(默认 POSIX)都会打印 37:

$ echo "$((1000/27))"
37

来自 [POSIX][1]:

仅需要有符号长整数算术。

您需要稍微更改数字才能在 ksh、zsh 和 yash 中获得浮点数学(不是 jsh、dash、ash、lksh、mksh 和 bash):

$ echo $((1000/27.0))
37.037037037037037

但要小心 zsh 优先级和精度:

$ for sh in ksh yash zsh; do $sh -c 'printf "%20d\n" "$(( 1<<63 - 5))"'; done
  288230376151711744
  288230376151711744
 9223372036854775803

$ for sh in ksh yash zsh; do $sh -c 'printf "%-20s\n" "$((1/10.0))"'; done
0.1                 
0.1                 
0.10000000000000001

意外的 zsh 截断限制:

$ zsh -c 'echo $((12345678901234567890));echo $((12345678901234567890123))'

zsh:1: number truncated after 19 digits: 12345678901234567890
1234567890123456789

zsh:1: number truncated after 22 digits: 12345678901234567890123
-1363962815083169260

bash 中有一个使用 printf 功能的解决方法(限制为 ~10 位数字):

$ bash -c 'printf "%.10f\n" "$(( 10**10*  1000/27  ))e-10"'
37.0370370370

但为什么还要麻烦有bc可用的:

$ echo '1000/27' | bc -l
37.03703703703703703703

[1]:仅需要有符号长整型运算。

答案4

没有专门使用 bash,但你应该可以bc使用:

# bc doesn't like exponential numbers in the manner provided.  It can be done, but this number is equivalent.
x=2.8026407
printf "1000 * %s" "$x" | bc

相关内容