IT story

bash에서 부동 소수점 나누기를 어떻게 사용합니까?

hot-time 2020. 5. 7. 08:02
반응형

bash에서 부동 소수점 나누기를 어떻게 사용합니까?


Bash 스크립트에서 두 이미지 너비를 나누려고하지만 bash는 0결과를 제공합니다.

RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))

나는 Bash 가이드를 공부 bc했고 인터넷에서 사용 하는 모든 예제에서 사용해야한다는 것을 알고있다 bc. 에서 echo내에서 같은 일을 넣어 시도 SCALE했지만 작동하지 않았다.

튜토리얼에서 찾은 예제는 다음과 같습니다.

echo "scale=2; ${userinput}" | bc 

Bash가 어떻게 플로트를 줄 수 0.5있습니까?


당신은 할 수 없습니다. bash는 단지 정수를 않습니다; 당신은 해야한다 와 같은 도구에 위임 bc.


당신은 이것을 할 수 있습니다 :

bc <<< 'scale=2; 100/3'
33.33

업데이트 20130926 : 당신은 사용할 수 있습니다 :

bc -l <<< '100/3' # saves a few hits

세게 때리다

다른 사람들이 지적했듯이 bash부동 소수점 산술을 지원하지 않지만 소수 자릿수와 같은 고정 소수점 트릭으로 소수점을 위조 할 수는 있습니다.

echo $(( 100 * 1 / 3 )) | sed 's/..$/.&/'

산출:

.33

비슷하지만 더 간결한 접근법에 대해서는 Nilfred의 답변참조하십시오 .

대안

언급 bcawk대안 외에도 다음이 있습니다.

절정

clisp -x '(/ 1.0 3)'

정리 된 출력으로 :

clisp --quiet -x '(/ 1.0 3)'

또는 stdin을 통해 :

echo '(/ 1.0 3)' | clisp --quiet | tail -n1

dc

echo 2k 1 3 /p | dc

천재 cli 계산기

echo 1/3.0 | genius

gnuplot

echo 'pr 1/3.' | gnuplot

jq

echo 1/3 | jq -nf /dev/stdin

또는:

jq -n 1/3

ksh

echo 'print $(( 1/3. ))' | ksh

루아

lua -e 'print(1/3)'

또는 stdin을 통해 :

echo 'print(1/3)' | lua

맥시마

echo '1/3,numer;' | maxima

정리 된 출력으로 :

echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'

마디

echo 1/3 | node -p

옥타브

echo 1/3 | octave

echo print 1/3 | perl

python2

echo print 1/3. | python2

python3

echo 'print(1/3)' | python3

아르 자형

echo 1/3 | R --no-save

정리 된 출력으로 :

echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'

루비

echo print 1/3.0 | ruby

wcalc

echo 1/3 | wcalc

정리 된 출력으로 :

echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2

zsh

echo 'print $(( 1/3. ))' | zsh

단위

units 1/3

컴팩트 한 출력으로 :

units --co 1/3

다른 출처

Stéphane Chazelas 는 Unix.SX 에서 비슷한 질문에 답변 했습니다.


marvin의 답변을 조금 개선 :

RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")

bc가 항상 설치된 패키지로 제공되는 것은 아닙니다.


bc의 대안으로 스크립트 내에서 awk를 사용할 수 있습니다.

예를 들면 다음과 같습니다.

echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'

In the above, " %.2f " tells the printf function to return a floating point number with two digits after the decimal place. I used echo to pipe in the variables as fields since awk operates properly on them. " $1 " and " $2 " refer to the first and second fields input into awk.

And you can store the result as some other variable using:

RESULT = `echo ...`

You could use bc by the -l option (the L letter)

RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)

It's perfect time to try zsh, an (almost) bash superset, with many additional nice features including floating point math. Here is what your example would be like in zsh:

% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875

This post may help you: bash - Worth switching to zsh for casual use?


Well, before float was a time where fixed decimals logic was used:

IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33

Last line is a bashim, if not using bash, try this code instead:

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

The rationale behind the code is: multiply by 100 before divide to get 2 decimals.


It's not really floating point, but if you want something that sets more than one result in one invocation of bc...

source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')

echo bc radius:$1 area:$a diameter:$d

computes the area and diameter of a circle whose radius is given in $1


There are scenarios in wich you cannot use bc becouse it might simply not be present, like in some cut down versions of busybox or embedded systems. In any case limiting outer dependencies is always a good thing to do so you can always add zeroes to the number being divided by (numerator), that is the same as multiplying by a power of 10 (you should choose a power of 10 according to the precision you need), that will make the division output an integer number. Once you have that integer treat it as a string and position the decimal point (moving it from right to left) a number of times equal to the power of ten you multiplied the numerator by. This is a simple way of obtaining float results by using only integer numbers.


If you found the variant of your preference you can also wrap it into a function.

Here I'm wrapping some bashism into a div function:

One liner:

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

Or multi line:

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
}

Now you have the function

div <dividend> <divisor> [<precision=2>]

and use it like

> div 1 2
.50

> div 273 123 5
2.21951

> x=$(div 22 7)
> echo $x
3.14

i know it's old, but too tempting. so, the answer is: you can't... but you kind of can. let's try this:

$IMG_WIDTH=1024
$IMG2_WIDTH=2048

$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))

like that you get 2 digits after the point, truncated (call it rounding to the lower, haha) in pure bash (no need to launch other processes). of course, if you only need one digit after the point you multiply by 10 and do modulo 10.

what this does:

  • first $((...)) does integer division;
  • second $((...)) does integer division on something 100 times larger, essentially moving your 2 digits to the left of the point, then (%) getting you only those 2 digits by doing modulo.

bonus track: bc version x 1000 took 1,8 seconds on my laptop, while the pure bash one took 0,016 seconds.


While you can't use floating point division in Bash you can use fixed point division. All that you need to do is multiply your integers by a power of 10 and then divide off the integer part and use a modulo operation to get the fractional part. Rounding as needed.

#!/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))

Use calc. It's the easiest I found example:

calc 1+1

 2

calc 1/10

 0.1

here is awk command: -F = field separator == +

echo "2.1+3.1" |  awk -F "+" '{print ($1+$2)}'

참고URL : https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash

반응형