shellで浮動小数点の計算をする方法

shellで普通に計算すると、どうしても整数で返ってくるため、少数値を扱うのに困ってしまいます。
ただ、浮動小数点を扱えない訳ではなく、特定のお作法を通してやる必要があるという事なんですね。
そこで、まあまあ簡単に少数値の計算を行える方法をご紹介します。
bcコマンドを使う
1 2 3 4 |
$ expr 2 - 1 > 1 $ expr 2.1 - 0.9 > expr: not a decimal number: '2.1' |
exprコマンドは整数専用なので、上記のように怒られてしまいます。
小数点も扱えるbcコマンドというのがあり、数値計算を行うコマンドです。
あまり使われることはないのですが、計算式において、色々と便利な機能を持っているので
使い慣れておくとかなり得することが多いでしょう。
小技
計算結果が1より少ない少数値の場合、.(ピリオド)の前が省略されるようです。
1 2 |
$ echo “1.1-0.9”|bc -l > .2 |
数値としては、整数の箇所にも0を付けたい場合は、awkを用いて以下のようにすることで対応可能になります。
1 2 |
$ echo “1.1-0.9”|bc -l|awk '{if($0~/^\./){print "0"$0}else{print $0}}' > 0.2 |
あれ?最初からawkでやればいいんでないか?
試しにやってみる
1 2 |
$ echo "2.1 - 1.9"|awk '{print $1 - $3}' > 0.2 |
演算子を含めて処理できるbcもいいが、数字を直接操作できるawkも魅力ですね。
しかも、整数の0までしっかりついてるし・・・orz
速度比較
エンジニアとして少し気になったので、bcとawkの速度比較を行なってみました。
bc.sh
1 2 3 4 5 6 |
#!/bin/bash A=0 for i in `seq 0 10000`;do A=`echo $i+$A|bc -l` done echo $A |
awk.sh
1 2 3 4 5 6 |
#!/bin/bash A=0 for i in `seq 0 10000`;do A=`echo "$i $A"|awk '{print $1+$2}'` done echo $A |
kakko.sh
1 2 3 4 5 6 |
#!/bin/bash A=0 for i in `seq 0 10000`;do A=$((A+i)) done echo $A |
解説
0〜10000までの数値を累計で足し込んでいく式をbc版とawk版で書いてみました。
それでは、実行!
実行結果
1 2 3 4 5 6 7 8 9 10 11 |
$ sh bc.sh 50005000 real 0m29.457s user 0m12.210s sys 0m20.309s $ sh awk.sh 50005000 real 0m31.180s user 0m13.158s sys 0m21.239s |
$ sh kakko.sh
50005000
real 0m0.077s
user 0m0.069s
sys 0m0.008s
0〜1000の値に変更して再度実行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ sh bc.sh 500500 real 0m2.886s user 0m1.222s sys 0m1.993s $ sh awk.sh 500500 real 0m3.253s user 0m1.362s sys 0m2.169s $ sh kakko.sh 500500 real 0m0.026s user 0m0.010s sys 0m0.012s |
まとめ
ほんのチョビっとだけbcコマンドの方が早いようですね。
しかし、驚愕なのは二重括弧のスピード!
桁が2つ近くも違う。
確かにawkやbcと違って、他のモジュールを読み込んでいないのでネイティブ動作だけだからでしょう。
ちなみに、exprを使うのがセオリーのようですが、awkやbcと同じでしょうね。
exprよりも((***))二重括弧を使うほうがスピードが早いらしい。
http://qiita.com/d_nishiyama85/items/a117d59a663cfcdea5e4
ということで、速度比較に加えてみました。