web-dev-qa-db-ja.com

bashで浮動小数点除算を使うにはどうすればいいですか?

Bashスクリプトで2つの画像幅を分割しようとしていますが、結果としてbashは0を返します。

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

私はBashガイドを勉強しました、そして私は私がbcを使うべきであることを知っています、彼らがbcを使うインターネットのすべての例で。 echoでは、SCALEに同じことを入れようとしましたが、うまくいきませんでした。

これが私がチュートリアルで見つけた例です:

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

どうやってBashから0.5のようなフロートをもらうことができますか?

187
Medya Gh

できません。 bashのみは整数を処理します。あなたbcのようなツールに委任しなければなりません

205

あなたはこれを行うことができます:

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

UPDATE20130926:あなたは使うことができます:

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

bash

他の人が指摘したように、bashは浮動小数点演算をサポートしていません。小数点以下2桁で

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

出力:

.33

似ているがより簡潔なアプローチについては、 Nilfredの答え を参照してください。

代替案

上記のbcおよびawkの選択肢に加えて、次のものもあります。

切り刻む

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

天才クリ電卓

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

Perl

echo print 1/3 | Perl

python2

echo print 1/3. | python2

python3

echo 'print(1/3)' | python3

R

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éphaneChazelasがUnix.SXで同様の質問 に答えました。

111
Thor

Marvinの答えを少し改善する:

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

bcは常にインストール済みパッケージとして来るわけではありません。

36
adrianlzt

-lオプション(b文字)でbcを使うことができます

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

Bcの代わりに、あなたのスクリプトの中でawkを使うことができます。

例えば:

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

上記の "%.2f"は、小数点以下2桁の浮動小数点数を返すようにprintf関数に指示します。 awkがそれらに対して正しく動作するので、私はechoを使って変数をフィールドとしてパイプインしました。 "$ 1"と "$ 2"は、awkに入力された最初と2番目のフィールドを参照します。

そして結果を他の変数として保存することができます。

RESULT = `echo ...`
25
marvin

浮動小数点演算を含む多くの追加機能を備えた(ほぼ)bashスーパーセットであるzshを試すのに最適な時期です。これがzshでの例です。

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

この記事はあなたを助けるかもしれません: bash - 何気ない用途にzshに切り替える価値はありますか?

17
Penghe Geng

まあ、floatの前に固定小数点論理が使用された時でした:

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

最後の行は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

コードの背後にある理論的根拠は、除算の前に100を掛けて小数点以下2桁を得ることです。

13
Nilfred

実際には浮動小数点数ではありませんが、1回の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

半径が$ 1で与えられる円の面積と直径を計算します

4
user3210339

ビジーボックスの一部のバージョンや組み込みシステムのように、bcが存在しない場合があるため、bcを使用できないシナリオがあります。どんな場合でも、外部の依存関係を制限することは常に良いことです。(分子)で割った数に常にゼロを加えることができます。これは、10のべき乗を掛けるのと同じです。あなたが必要とする精度)、それは除算を整数にします。整数が文字列として扱われたら、小数点の位置を(右から左に移動させて)10の累乗に等しい回数にします(分子を掛けたもの)。これは、整数のみを使用してfloatの結果を取得する簡単な方法です。

4
Daniel J.

あなたがあなたの好みの変種を見つけたなら、あなたはそれを関数にラップすることもできます。

ここで私は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;}

または複数行:

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
}

今、あなたは機能を持っています

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

そしてそれを好きに使う

> div 1 2
.50

> div 273 123 5
2.21951

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

私はそれが古いことを知っていますが、あまりにも魅力的です。そのため、答えは次のとおりです。これを試してみましょう:

$IMG_WIDTH=1024
$IMG2_WIDTH=2048

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

このように、ポイントの後に2桁の数字を取得し、純粋なbashで切り捨てられます(下への丸めと呼びます)(他のプロセスを起動する必要はありません)。もちろん、ポイントの後に1桁しか必要としない場合は、10を掛けて10を法とします。

これが何をするのか:

  • 最初の$((...))は整数除算を行います。
  • 2番目の$((...))は、100倍大きいもので整数除算を行い、基本的に2桁をポイントの左に移動し、(%)モジュロを行うことでこれら2桁のみを取得します。

ボーナストラック:bcバージョンx 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))
1

Calcを使用してください。これは私が見つけた最も簡単な例です。

計算1 + 1

 2

計算1/10

 0.1
1
Camila Pereira

これがawkコマンドです。-F =フィールド区切り文字== +

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