Med*_* Gh 211 floating-point bash arithmetic-expressions
我试图在Bash脚本中划分两个图像宽度,但bash给出0
了结果:
RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))
Run Code Online (Sandbox Code Playgroud)
我研究了Bash指南,我知道我应该使用它bc
,在他们使用的互联网的所有例子中bc
.在echo
我试图把同样的东西放在我的,SCALE
但它没有奏效.
以下是我在教程中找到的示例:
echo "scale=2; ${userinput}" | bc
Run Code Online (Sandbox Code Playgroud)
我怎么能让Bash给我一个漂浮0.5
?
Ign*_*ams 218
你不能.bash 只做整数; 你必须委托给像这样的工具bc
.
aay*_*ubi 177
你可以这样做:
bc <<< 'scale=2; 100/3'
33.33
Run Code Online (Sandbox Code Playgroud)
更新 20130926
:您可以使用:
bc -l <<< '100/3' # saves a few hits
Run Code Online (Sandbox Code Playgroud)
Tho*_*hor 125
正如其他人所指出的,bash
不支持浮点运算,虽然你可以用一些固定的十进制技巧伪造它,例如有两个小数:
echo $(( 100 * 1 / 3 )) | sed 's/..$/.&/'
Run Code Online (Sandbox Code Playgroud)
输出:
.33
Run Code Online (Sandbox Code Playgroud)
有关类似但更简洁的方法,请参阅Nilfred的答案.
除了上面提到的bc
和awk
替代方案之外,还有以下内容:
clisp -x '(/ 1.0 3)'
Run Code Online (Sandbox Code Playgroud)
清理输出:
clisp --quiet -x '(/ 1.0 3)'
Run Code Online (Sandbox Code Playgroud)
或通过stdin:
echo '(/ 1.0 3)' | clisp --quiet | tail -n1
Run Code Online (Sandbox Code Playgroud)
echo 2k 1 3 /p | dc
Run Code Online (Sandbox Code Playgroud)
echo 1/3.0 | genius
Run Code Online (Sandbox Code Playgroud)
echo 'pr 1/3.' | gnuplot
Run Code Online (Sandbox Code Playgroud)
echo 1/3 | jq -nf /dev/stdin
Run Code Online (Sandbox Code Playgroud)
要么:
jq -n 1/3
Run Code Online (Sandbox Code Playgroud)
echo 'print $(( 1/3. ))' | ksh
Run Code Online (Sandbox Code Playgroud)
lua -e 'print(1/3)'
Run Code Online (Sandbox Code Playgroud)
或通过stdin:
echo 'print(1/3)' | lua
Run Code Online (Sandbox Code Playgroud)
echo '1/3,numer;' | maxima
Run Code Online (Sandbox Code Playgroud)
清理输出:
echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'
Run Code Online (Sandbox Code Playgroud)
echo 1/3 | node -p
Run Code Online (Sandbox Code Playgroud)
echo 1/3 | octave
Run Code Online (Sandbox Code Playgroud)
echo print 1/3 | perl
Run Code Online (Sandbox Code Playgroud)
echo print 1/3. | python2
Run Code Online (Sandbox Code Playgroud)
echo 'print(1/3)' | python3
Run Code Online (Sandbox Code Playgroud)
清理输出:
echo 1/3 | R --no-save
Run Code Online (Sandbox Code Playgroud)
echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'
Run Code Online (Sandbox Code Playgroud)
echo print 1/3.0 | ruby
Run Code Online (Sandbox Code Playgroud)
清理输出:
echo 1/3 | wcalc
Run Code Online (Sandbox Code Playgroud)
echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2
Run Code Online (Sandbox Code Playgroud)
StéphaneChazelas在Unix.SX上 回答了类似的问题.
adr*_*lzt 39
改善马文的答案:
RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")
Run Code Online (Sandbox Code Playgroud)
bc并不总是作为安装包.
use*_*742 30
您可以通过-l
选项(L字母)使用bc
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)
Run Code Online (Sandbox Code Playgroud)
mar*_*vin 28
作为bc的替代方案,您可以在脚本中使用awk.
例如:
echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'
Run Code Online (Sandbox Code Playgroud)
在上面,"%.2f"告诉printf函数返回小数位后两位数的浮点数.我使用echo来将变量作为字段输入管道,因为awk在它们上运行正常."$ 1"和"$ 2"指的是输入awk的第一个和第二个字段.
您可以使用以下结果将结果存储为其他变量:
RESULT = `echo ...`
Run Code Online (Sandbox Code Playgroud)
Pen*_*eng 18
现在是尝试zsh(一个(几乎)bash超集)的最佳时机,还有许多其他不错的功能,包括浮点数学.以下是您在zsh中的示例:
% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875
Run Code Online (Sandbox Code Playgroud)
这篇文章可能会对你有所帮助:bash - 值得随意使用zsh切换到zsh吗?
小智 14
好吧,在float之前是使用固定小数逻辑的时间:
IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33
Run Code Online (Sandbox Code Playgroud)
最后一行是bashim,如果不使用bash,请尝试使用以下代码:
IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33
Run Code Online (Sandbox Code Playgroud)
代码背后的基本原理是:在除以前乘以100得到2位小数.
如何在 bash 中进行浮点计算:
这里不像最受欢迎的示例之一那样在命令中使用“ here strings ”( <<<
) ,而是我最喜欢的浮点示例,就来自手册页的部分(请参阅参考资料 手册页)。bc
bc
EXAMPLES
bc
man bc
在开始之前,请知道 pi 的方程是:pi = 4*atan(1)
。a()
下面是 的bc
数学函数atan()
。
这是如何将浮点计算的结果存储到 bash 变量中——在本例中存储到名为 的变量中pi
。请注意,scale=10
在本例中将精度的小数位数设置为 10。此位之后的任何小数位都将被截断。
pi="$(echo "scale=10; 4*a(1)" | bc -l)"
Run Code Online (Sandbox Code Playgroud)
现在,要使用一行代码来打印该变量的值,只需将该echo
命令添加到末尾作为后续命令,如下所示。请注意小数点后 10 位的截断,如下所示:
pi="$(echo "scale=10; 4*a(1)" | bc -l)"; echo "$pi"
Run Code Online (Sandbox Code Playgroud)
输出:
3.1415926532
Run Code Online (Sandbox Code Playgroud)
最后,让我们进行一些四舍五入。这里我们将使用该printf
函数四舍五入到小数点后 4 位。请注意,3.14159...
现在的轮次为3.1416
。由于我们进行四舍五入,我们不再需要使用scale=10
截断到小数点后 10 位,因此我们只需删除该部分即可。这是最终的解决方案:
3.1415926532
Run Code Online (Sandbox Code Playgroud)
输出:
3.1416
Run Code Online (Sandbox Code Playgroud)
测量和打印运行时间:
测量和打印程序的运行时间是上述技术的另一个非常好的应用和演示。
(另请参阅我的其他答案)。
方法如下。请注意,dt_min
从0.01666666666...
to舍入0.017
:
pi="$(printf "%.4f" $(echo "4*a(1)" | bc -l))"; echo "$pi"
Run Code Online (Sandbox Code Playgroud)
输出:
dt_sec = 1; dt_min = 0.017
Run Code Online (Sandbox Code Playgroud)
+
、-
、/
、*
、**
、&
、&&
、<<
等)以及算术扩展小智 6
我知道它很旧,但太诱人了。所以,答案是:你不能……但你可以。让我们试试这个:
\n$IMG_WIDTH=1024\n$IMG2_WIDTH=2048\n\n$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))"\n
Run Code Online (Sandbox Code Playgroud)\n这样,您会在纯 bash 中得到点后的 2 位数字,并被截断(称为四舍五入)(无需启动其他进程)。当然,如果您只需要该点后的一位数字,则乘以 10 并取模 10。
\n这是做什么的:
\n$((...))
进行整数除法;$((...))
对 100 倍大的东西进行整数除法,本质上是将你的 2 位数字移到该点的左侧,然后 ( %
) 通过取模得到这 2 位数字。额外曲目:bc
\xc3\x97 1000 版本在我的笔记本电脑上花了 1.8 秒,而纯bash
版本花了 0.016 秒。
虽然您不能在 Bash 中使用浮点除法,但您可以使用定点除法。您需要做的就是将整数乘以 10 的幂,然后除掉整数部分并使用模运算得到小数部分。根据需要舍入。
#!/bin/bash
n=$1
d=$2
# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))
Run Code Online (Sandbox Code Playgroud)
如果您找到了您偏好的变体,您还可以将其包装到一个函数中。
在这里,我将一些 bashism 包装到一个 div 函数中:
一个班轮:
function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}
Run Code Online (Sandbox Code Playgroud)
或多行:
function div {
local _d=${3:-2}
local _n=0000000000
_n=${_n:0:$_d}
local _r=$(($1$_n/$2))
_r=${_r:0:-$_d}.${_r: -$_d}
echo $_r
}
Run Code Online (Sandbox Code Playgroud)
现在你有了这个功能
div <dividend> <divisor> [<precision=2>]
Run Code Online (Sandbox Code Playgroud)
并像使用它一样
> div 1 2
.50
> div 273 123 5
2.21951
> x=$(div 22 7)
> echo $x
3.14
Run Code Online (Sandbox Code Playgroud)
更新 我添加了一个小脚本,它为您提供了 bash 浮点数的基本操作:
用法:
> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333
Run Code Online (Sandbox Code Playgroud)
这里的脚本:
#!/bin/bash
__op() {
local z=00000000000000000000000000000000
local a1=${1%.*}
local x1=${1//./}
local n1=$((${#x1}-${#a1}))
local a2=${2%.*}
local x2=${2//./}
local n2=$((${#x2}-${#a2}))
local n=$n1
if (($n1 < $n2)); then
local n=$n2
x1=$x1${z:0:$(($n2-$n1))}
fi
if (($n1 > $n2)); then
x2=$x2${z:0:$(($n1-$n2))}
fi
if [ "$3" == "/" ]; then
x1=$x1${z:0:$n}
fi
local r=$(($x1"$3"$x2))
local l=$((${#r}-$n))
if [ "$3" == "*" ]; then
l=$(($l-$n))
fi
echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}
Run Code Online (Sandbox Code Playgroud)
对于那些试图用接受的答案计算百分比但失去精度的人:
如果你运行这个:
echo "scale=2; (100/180) * 180" | bc
Run Code Online (Sandbox Code Playgroud)
你得到的99.00
只是,这会失去精度。
如果你这样运行:
echo "result = (100/180) * 180; scale=2; result / 1" | bc -l
Run Code Online (Sandbox Code Playgroud)
现在你得到了99.99
。
因为您仅在打印时进行缩放。
参考这里
归档时间: |
|
查看次数: |
281568 次 |
最近记录: |