shellで普通に計算すると、どうしても整数で返ってくるため、少数値を扱うのに困ってしまいます。
ただ、浮動小数点を扱えない訳ではなく、特定のお作法を通してやる必要があるという事なんですね。
そこで、まあまあ簡単に少数値の計算を行える方法をご紹介します。
bcコマンドを使う
$ expr 2 - 1
> 1
$ expr 2.1 - 0.9
> expr: not a decimal number: '2.1'
exprコマンドは整数専用なので、上記のように怒られてしまいます。
小数点も扱えるbcコマンドというのがあり、数値計算を行うコマンドです。
あまり使われることはないのですが、計算式において、色々と便利な機能を持っているので
使い慣れておくとかなり得することが多いでしょう。
小技
計算結果が1より少ない少数値の場合、.(ピリオド)の前が省略されるようです。
$ echo “1.1-0.9”|bc -l
> .2
数値としては、整数の箇所にも0を付けたい場合は、awkを用いて以下のようにすることで対応可能になります。
$ echo “1.1-0.9”|bc -l|awk '{if($0~/^\./){print "0"$0}else{print $0}}'
> 0.2
あれ?最初からawkでやればいいんでないか?
試しにやってみる
$ echo "2.1 - 1.9"|awk '{print $1 - $3}'
> 0.2
演算子を含めて処理できるbcもいいが、数字を直接操作できるawkも魅力ですね。
しかも、整数の0までしっかりついてるし・・・orz
速度比較
エンジニアとして少し気になったので、bcとawkの速度比較を行なってみました。
#!/bin/bash
A=0
for i in `seq 0 10000`;do
A=`echo $i+$A|bc -l`
done
echo $A
#!/bin/bash
A=0
for i in `seq 0 10000`;do
A=`echo "$i $A"|awk '{print $1+$2}'`
done
echo $A
#!/bin/bash
A=0
for i in `seq 0 10000`;do
A=$((A+i))
done
echo $A
解説
0〜10000までの数値を累計で足し込んでいく式をbc版とawk版で書いてみました。
それでは、実行!
実行結果
$ 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の値に変更して再度実行
$ 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と同じでしょうね。