シェルで計算した時のメモです。Ubuntu16とTiny Core LinuxのCoreのインストール直後(と思う)状態で試しています。ここでいう標準シェルとはUbuntuならbash、Tiny Core Linuxならashを想定しています。
まずは整数の計算
expr
コマンドで計算することができます。
$ echo $(expr 1 + 2)
3
$(())
でも計算できます。
$ echo $((1 + 2))
3
Tiny Core Linuxでの注意点
Tiny Core Linuxで$(())
を使う際は書き方に注意が必要のようです。以下はマイナスの数値を引き算する例ですが、書き方によってはarithmetic syntax errorになってしまうようです。
$ a=1;b=-2
$ echo $(($a-$b))
-sh: arithmetic syntax error
$ echo $(($a - $b))
3
$ echo $((a-b))
3
また10桁を超えたあたりから結果がおかしくなるようです。Tiny Core Linuxで10桁を超える場合はexpr
コマンドを使う必要がありそうです。
$ echo $(expr 12345678901 + 2)
12345678903
$ echo $((12345678901 + 2))
2
実数は使えません
残念ながらexpr
も$(())
も小数点を含むとエラーになります。これはUbuntuでもTiny Core Linuxでも同じです。
$ echo $(expr 1.5 + 2)
expr: non-integer argument
$ echo $((1.5 + 2))
bash: 1.5 + 2: syntax error: invalid arithmetic operator (error token is ".5 + 2")
小数点を含んだもののも計算
bcコマンド
bc
コマンドを使えば小数点を含む数値も計算できます。Tiny Core LinuxのCoreと呼ばれる最小構成の素の状態にはbc
コマンドは含まれませんので、この方法はTiny Core LinuxのCoreでは使えません。※もちろんbcパッケージをインストールすれば使えます。
$ echo $(echo '1.5 + 2' | bc)
3.5
-l
オプションをつければsin、cos関数も使えます。
$ echo $(echo "s(80*3.14/180)" | bc -l)
.98468459013058331641
$ echo $(echo "c(80*3.14/180)" | bc -l)
.17434522637389628631
awkコマンド
awk
コマンドのprintは計算式をサポートているだけでなく、小数点を含んだ数値もsin、cosといった関数も使えて、Tiny Core Linuxでも使えます。
$ echo $(echo '1.5 2' | awk '{print $1 + $2}')
3.5
$ echo $(echo "80" | awk '{print sin($1*3.14/180)}')
0.984685
$ echo $(echo "80" | awk '{print cos($1*3.14/180)}')
0.174345
awk
の場合入力が必要なんですが、以下のようにヌル文字を渡せば計算式がそのまま書けます。個人的にはecho
で値を渡す方が関数ぽく書けて好きですが…
$ echo $(echo "" | awk '{print sin(80*3.14/180)}')
0.984685
$ echo $(echo "" | awk '{print cos(80*3.14/180)}')
0.174345
実行速度の違い
簡単なスクリプトを作って実行速度を測ってみました。
テスト | Ubuntu16 | TinyCoreLinux v7 |
---|---|---|
整数(expr) | 0.168544sec | 0.133583sec |
整数($(())) | 0.00392652sec | 0.00325775sec |
整数(bc) | 0.255331sec | error |
整数(awk) | 0.228399sec | 0.20771sec |
実数(bc) | 0.269739sec | error |
実数(awk) | 0.230662sec | 0.205647sec |
関数(bc) | 0.32672sec | error |
関数(awk) | 0.230426sec | 0.209495sec |
結果として整数の場合ならexpr
よりも$(())
の方が速くて、実数の場合ならbc
コマンドよりawk
コマンドの方が速いようです。
整数計算が10桁以下なら$(())
、10桁を超えるならexpr
、実数計算ならawk
コマンドを使うようにすればUbuntuでもTiny Core Linuxでも良い結果が出そうです。
速度測定スクリプトのソース
以下が今回使用した速度測定スクリプトです。このスクリプトではナノ秒を取得するためにdate
コマンドの%N
を使っているのですが、Tiny Core Linux v8では%N
が使えないようですのでv8では使えません。
#!/bin/sh
int_expr() {
a=0
for i in $(seq 0 99);do
a=$(expr $a + $i)
done
echo $a
}
int_brackets() {
a=0
for i in $(seq 0 99);do
a=$(($a + $i))
done
echo $a
}
int_bc() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a + $i" | bc)
done
echo $a
}
int_awk() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a $i" | awk '{print $1+$2}')
done
echo $a
}
real_bc() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a+$i*0.5" | bc -l)
done
echo $a
}
real_awk() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a $i" | awk '{print $1+$2*0.5}')
done
echo $a
}
func_bc() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a+s($i*3.14/180)+c($i*3.14/180)" | bc -l)
done
echo $a
}
func_awk() {
a=0
for i in $(seq 0 99);do
a=$(echo "$a $i" | awk '{print $1+sin($2*3.14/180)+cos($2*3.14/180)}')
done
echo $a
}
set_time() {
start_time=$(date +'%s.%N')
}
echo_time() {
end_time=$(date +'%s.%N')
echo $(echo "$start_time $end_time"|awk '{print $2-$1}')'sec'
}
set_time;int_expr;echo_time
set_time;int_brackets;echo_time
set_time;int_bc;echo_time
set_time;int_awk;echo_time
set_time;real_bc;echo_time
set_time;real_awk;echo_time
set_time;func_bc;echo_time
set_time;func_awk;echo_time