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


242

Bashスクリプトで2つの画像の幅を分割しようとしていますが、bashを実行0すると結果が得られます。

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

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

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

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

どのようにしてBashに私にフロートを与えることができ0.5ますか?


9
スクリプトで浮動小数点演算を行おうとするすべての人へのコメントです。自分で質問してください。本当に浮動小数点演算が必要ですか?時にはあなたは本当になしでうまくいくことができます。たとえば、BashFAQ / 022の最後の部分を参照してください。
gniourf_gniourf 2015

回答:


242

できません。bash は整数のみを実行します。などのツールに委任する必要ありますbc


8
bcなどのツールを委任して、回答をRESULT変数に入れるにはどうすればよいですか?
Medya Gh

2
VAR = $(echo "scale = 2; $(($ IMG_WIDTH / $ IMG2_WIDTH))" | bc)のような意味ですか?
Medya Gh

54
@Shevin VAR=$(echo "scale=2; $IMG_WIDTH/$IMG2_WIDTH" | bc)またはVAR=$(bc <<<"scale=2;$IMG_WIDTH/$IMG2_WIDTH")$(())なし(二重括弧); コマンドを実行する前にbashによって展開される
Nahuel Fouilleul

4
確かに、しかしawkは一般にシステムにすでにインストールされている可能性が高いです。
CMCDragonkai 2014年

9
@NahuelFouilleulここで一番良い答えがあります。本当に独自の答えであり、答えとして受け入れられるべきです。この特定の行は非常に役に立ちました:VAR = $(bc <<< "scale = 2; $ IMG_WIDTH / $ IMG2_WIDTH")
David

197

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

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

UPDATE 20130926:以下を使用できます。

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

8
...そして多くの桁を追加します。少なくとも私のマシンでは、これは33.33333333333333333333を生成し、前者は33.33を生成します。
Andreas Spindler 2014

12
@AndreasSpindler古い投稿のようなものですが、誰かが知りたい場合は、scaleコマンドを適用することでこれを変更できます。bc -l <<< 'scale=2; 100/3'
マーティ、

scale = 0を使用して、後でbashで使用するために整数を取得したい場合は注意してください。v1.06.95以降、入力数値に小数部がある場合、bcは何らかの理由でスケール変数を無視します。これはドキュメントにあるかもしれませんが、見つかりませんでした。試してみてください:echo $(bc -l <​​<< 'scale = 0; 1 * 3.3333')
Greg Bell

1
言うのmanページを@GregBell Unless specifically mentioned the scale of the result is the maximum scale of the expressions involved.そしてための余分な注意事項があり/オペレータは:The scale of the result is the value of the variable scale.
PSMITH

2
@psmith、ありがとう。興味深いことに、/は「結果のスケールは可変スケールの値である」と述べていますが、乗算についてはそうではありません。私のより良い例:bc <<< 'scale=1; 1*3.00001' なんらかの理由でスケールは本当に5、 bc <<< 'scale=1; 1/3.000001' スケールは1です。興味深いことに、1で割ると直線になります: bc <<< 'scale=1; 1*3.00001/1'スケールは1
グレッグベル

136

バッシュ

他の人が指摘しているように、bashは浮動小数点演算をサポートしていませんが、小数点以下2桁など、いくつかの固定された10進数のトリックで偽造することができます。

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

出力:

.33

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

代替案

言及さbcれたawk代替案のほかに、次のものもあります。

クリスプ

clisp -x '(/ 1.0 3)'

クリーンアップされた出力:

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

または標準入力を介して:

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

DC

echo 2k 1 3 /p | dc

天才CLI計算機

echo 1/3.0 | genius

ゴーストスクリプト

echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p' 

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)'

または標準入力を介して:

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 で同様の質問に回答しました。


9
すばらしい答えです。私はそれが質問の数年後に投稿されたことを知っていますが、受け入れられた答えであることはより価値があります。
ブライアンクライン

2
あなたが持っている場合、それの価値ではなく、バッシュのzshの中で、あなたのスクリプトを記述することを検討し、可能なのzsh
アンドレアCorbellini

gnuplotに
賛成

いいリスト。特にecho 1/3 | node -p短いです。
Johnny Wong、

39

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

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

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


4
awkスクリプトは、exit入力ストリームから読み取れないようにするためにを必要とします。また、awkの-vフラグを使用して、傾いたつまようじ症候群を予防することをお勧めします。So:RESULT=$(awk -v dividend="${IMG_WIDTH}" -v divisor="${IMG2_WIDTH}" 'BEGIN {printf "%.2f", dividend/divisor; exit(0)}')
aecolley 2015年

2
これを行うためのより厄介な方法は、入力ストリームから引数を読み取ることです RESULT=$(awk '{printf("result= %.2f\n",$1/$2)}' <<<" $IMG_WIDTH $IMG2_WIDTH "
jmster

1
bcPOSIXの一部であり、通常はプリインストールされています。
fuz 2015

これは、windows 7でgit bashを使用して動作しました...感謝:)
ビースト


28

bcの代わりに、スクリプト内でawkを使用できます。

例えば:

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

上記の "%.2f"は、printf関数に、小数点以下2桁の浮動小数点数を返すように指示します。awkが適切に動作するため、エコーを使用して変数をフィールドとしてパイプします。「$ 1」と「$ 2」は、awkに入力される最初と2番目のフィールドを参照します。

そして、あなたは結果を他の変数として保存することができます:

RESULT = `echo ...`

優れた!ありがとう。これは、bcが存在しない組み込み環境に役立ちます。あなたは私にクロスコンパイル時間を節約しました。
enthusiasticgeek

19

(ほとんど)bashスーパーセットであるzshを試す絶好の機会です。浮動小数点演算を含む多くの優れた機能が追加されています。zshでの例は次のようになります。

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

この投稿はあなたを助けるかもしれません:bash-カジュアルな使用のためにzshに切り替える価値はありますか?


3
私はzshの大ファンで、過去4年間使用していますが、ここではインタラクティブな使用に重点を置いています。残念ながら、zshを必要とするスクリプトは、通常は標準ではないため、さまざまなマシンのセット間で移植性が低くなります(公平を期すために、多分それは大丈夫です。OPは、それがどのように使用されるかについては十分に述べていません)。
ブライアンクライン

17

まあ、フロートが固定小数点ロジックが使用されたときは:

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

最後の行はバシムです。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

コードの背後にある理論的根拠は、2の小数を取得するために除算する前に100を掛けます。


5

好みのバリアントを見つけたら、それを関数にラップすることもできます。

ここでは、いくつかのバシズムを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

更新 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

そしてここにスクリプト:

#!/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 / ;}

1
local _d=${3:-2}よりシンプル
KamilCuk

4

これは実際には浮動小数点ではありませんが、bcの1回の呼び出しで複数の結果を設定するものが必要な場合は...

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

bcを使用できないシナリオがあります。busyboxや組み込みシステムの一部の削減バージョンのように、単に存在しない可能性があるためです。いずれの場合でも、外部依存関係を制限することは常に良いことです。そのため、(数値)で除算される数値に常にゼロを追加できます。これは、10の累乗を乗算するのと同じです(10の累乗は、必要な精度)、除算の出力を整数にします。その整数を文字列として扱い、小数点を(右から左に移動して)分子の10の累乗に等しい回数だけ配置します。これは、整数のみを使用して浮動小数点の結果を取得する簡単な方法です。


1
BusyboxにもAwkがあります。おそらく、ここにもっと目立つAwkの答えがあるはずです。
tripleee 2018年

4

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))

4

私はそれが古いことを知っていますが、あまりにも魅力的です。だから、答えは:あなたはできません...しかし、あなたは一種のことができます。これを試してみましょう:

$IMG_WIDTH=1024
$IMG2_WIDTH=2048

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

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

これは何をしますか:

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

ボーナストラック:bcバージョンx 1000は私のラップトップで1,8秒かかりましたが、純粋なbashのものは0,016秒かかりました。


3

bashで浮動小数点計算を行う方法:

コマンドで" here strings "(<<<)を使用する代わりにbc最も支持されている例の 1つが行うように、マニュアルページbcEXAMPLESセクションから直接、私のお気に入りの浮動小数点の例を示しbcます(man bcマニュアルページについてはを参照)。

始める前に、piの方程式は次のとおりであることを確認してくださいpi = 4*atan(1)a()以下はのbc数学関数ですatan()

  1. これは、浮動小数点計算の結果をbash変数(この場合はと呼ばれる変数)に格納する方法piです。scale=10この場合、は精度の10進数の桁数を10に設定することに注意してください。この場所の後の小数は切り捨てられます。

    pi=$(echo "scale=10; 4*a(1)" | bc -l)
  2. 次に、この変数の値も出力する1行のコードを作成するには、echo次のように、コマンドをフォローアップコマンドとして最後に追加するだけです。以下のように、小数点以下10桁で切り捨てられていることに注意してください。

    pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
    3.1415926532
  3. 最後に、端数処理を行います。ここでは、printf関数を使用して小数点以下4桁に丸めます。3.14159...今度はに丸められることに注意してください3.1416。丸めているので、を使用scale=10して小数点以下10桁に切り捨てる必要はないので、その部分を削除します。これが最終的な解決策です:

    pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
    3.1416

上記の手法のもう1つの非常に優れたアプリケーションとデモは、実行時間の測定と印刷です。

dt_minから0.01666666666...に丸められることに注意してください0.017

start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017

関連:


1
詳細な例と
ユース


2

受け入れられた答えでパーセンテージを計算しようとしているが、精度を失っている場合:

これを実行すると:

echo "scale=2; (100/180) * 180" | bc

あなた99.00だけが得ます、それは精度を失っています。

このように実行すると、次のようになります。

echo "result = (100/180) * 180; scale=2; result / 1" | bc -l

今あなたが得る99.99

印刷時のみスケーリングしているからです。

こちらをご参照ください


1

** bash /シェルでの注入安全な浮動小数点演算**

注:この回答の焦点は、bash(または他のシェル)で数学を実行するための注入安全なソリューションのアイデアを提供することです。もちろん、これを使用して、高度な文字列処理などを実行するための微調整を行うこともできます。

提示されたソリューションのほとんどは、外部データ(変数、ファイル、コマンドライン、環境変数)を使用して、小さなスクリプトレットをその場で構築します。外部入力を使用して、悪意のあるコードをエンジンに挿入できます。

以下は、さまざまな言語を使用して基本的な数学計算を実行する場合の比較で、結果は浮動小数点になります。A + B * 0.1(浮動小数点として)を計算します。

すべてのソリューションは、維持が非常に難しい動的スクリプトレットの作成を回避し、代わりに静的プログラムを使用して、指定された変数にパラメーターを渡します。それらは、特殊文字を含むパラメーターを安全に処理します-コードインジェクションの可能性を減らします。例外は、入出力機能を提供しない「BC」です。

例外は 'bc'で、これは入出力を提供しません。すべてのデータはプログラムを介してstdinにあり、すべての出力はstdoutに送られます。すべての計算はサンドボックスで実行され、副作用(ファイルを開くなど)を許可しません。理論的には、設計により安全な注入!

A=5.2
B=4.3

# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'

# Perl
perl -e '($A,$B) = @ARGV ; print $A + $B * 0.1' "$A" "$B"

# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"

# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"

# BC
bc <<< "scale=1 ; $A + $B * 0.1"

任意の引数を持つpython3の場合: python3 -c 'import sys ; *a, = map(float, sys.argv[1:]) ; print(a[0] + a[1]*0.1 + a[2])' "$A" "$B""4200.0" ==> 4205.63
WiringHarness

0

ここにawkコマンドがあります:-F =フィールドセパレーター== +

echo "2.1+3.1" |  awk -F "+" '{print ($1+$2)}'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.