このscriptに与えるのは0% (消灯)〜100% (フルパワー)の数値 (0-100)で、これを実際のPWM制御に使っている0-255に変換したい。つまり、percentage → 実際の数値の変換である。この時、percentageもPWMの数値も整数とする。
Shell scriptで計算するには主に次の3つの選択肢がある:
* expr
* bash/zshなどのbuiltin → $(( EXPR )) ※shebang注意 (/bin/shだと使えなかったりする)
* bc
exprは整数演算しかできないし、shell builtinは整数への丸め方が分からないのでbcを使っていたのだが、最終的には「小数点以下の切り捨てを回避できればどれでもok」だと分かった。
うまくいったやりかた
expr
% expr 76 \* 255 \/ 100
193
exprに与える式はescapeしてある (*とか/とか)
shell builtin
zshで実験した:% echo $((76 * 255 / 100))
193
exprと違いescapeする必要はない。
bc
% echo "76 * 255 / 100" | bc193
最初試した間違っているやりかた
percentage = A / B * 100
という式から:
A = percentage / 100 * B
と変形してそのままimplementすると、percentage / 100の結果が小数点以下の数値になり、小数点以下の演算を扱えない場合に切り捨てられて0になる。例えばbcで:
0
となるのはこのため。無論、3 / 255 * 100 = 1.1765... なので (数学的には) この結果はおかしい (少なくとも意図した結果ではない)。
bcの場合はexprと違って小数点以下の数も扱えるのだが、この場合はscale=0の効果で 3 / 255 = 0.0039...が0になるので、その後から幾ら数を掛けようと0にしかならない訳だ。
そこで、乗算と除算は (実数の範囲では) 順序を変えても計算結果が変わらない性質を利用する。
A = percentage * B / 100
つまり、3 * 100 = 300 を計算してから 255で割れば、無理なく整数部分を取り出せる:
A = percentage * B / 100
つまり、3 * 100 = 300 を計算してから 255で割れば、無理なく整数部分を取り出せる:
% echo "scale=0; 3 * 100 / 255" | bc -l
1
これが望んだ結果である。
蛇足
乗算の順序に拘るような学校教育を真に受けた子供達が、結果の同じ演算の順序を変えることを思い付かずにこの手の問題を解決できなかった、なんて理由でプログラミング教育や実際のコーディングに悪影響が出なければ良いなとつくづく思う。
まあ、大抵のプログラミング言語は小数点以下も扱えるし問題ないか……。