hello worldより「コラッツの問題」書くほうがいろいろ学べそうという投稿でシェルスクリプトでコラッツの問題を書きました。
#!/bin/sh
collatz() {
n=$1
echo $n
sleep 0.5s
if [ `echo "$n % 2" | bc` -eq 1 ] && [ $n != "1" ]; then
collatz `echo "3 * $n + 1" | bc`
elif [ `echo $n % 2 | bc` -eq 0 ]; then
collatz `echo $n / 2 | bc`
fi
}
collatz $1
この投稿で
99999999999999999999999999999999999999999999999999999999999999995まで計算出来ました。
と書いたのですが、
99999999999999999999999999999999999999999999999999999999999999996はなぜダメだったかというとエラーが出ていたのです。
※環境はmacです。
99999999999999999999999999999999999999999999999999999999999999996
49999999999999999999999999999999999999999999999999999999999999998
・・・(省略
36947297000885009765624999999999999999999999999999999999999999999999
11084189100265502929687499999999999999999999999999999999999999999999\
(standard_in) 1: illegal character: \
collatz.sh: line 6: [: -eq: unary operator expected
(standard_in) 1: illegal character: \
collatz.sh: line 8: [: -eq: unary operator expected
68桁でバックスラッシュが入ってしまい数値化できずエラーというところでしょうか。
「なんで68桁でバックスラッシュが入るのかなぁ」と思ってbcに大きい値を入れてみると
$ echo 9999999999999999999999999999999999999999999999999999999999999999999999999999999 | bc
99999999999999999999999999999999999999999999999999999999999999999999\
99999999999
バックスラッシュが入りました。
どうやらbcが68桁でバックスラッシュを入れているみたいです。
bcのmanを見る
man見たら何かわかるだろと思い、「bc man」でググって一番上のMan page of bc - JM Projectへ
環境変数の項でなんとなく関係ありそうな説明を発見
BC_LINE_LENGTH
数字を出力するときの 1 行の文字数を整数で指定します。 数字が長過ぎると、バックスラッシュと改行を含めた出力となります。
これっぽい
現在のBC_LINE_LENGTHを見ようと
$ echo $BC_LINE_LENGTH
としてみても空行が返されるだけでした。
デフォルトで68桁なのでしょうか?
「BC_LINE_LENGTH」でググると
$ BC_LINE_LENGTH=999 echo 9999999999999999999999999999999999999999999999999999999999999999999999999999999 | bc
か
$ export BC_LINE_LENGTH=999
で変えられると書いてありました。
環境変数はなるべく汚したくなかったので最初は前者でやったのですが効きませんでした。
$ BC_LINE_LENGTH=999 echo 9999999999999999999999999999999999999999999999999999999999999999999999999999999 | bc
99999999999999999999999999999999999999999999999999999999999999999999\
99999999999
バックスラッシュで改行されます。
なので今度は後者で。
$ export BC_LINE_LENGTH=999
$ echo 9999999999999999999999999999999999999999999999999999999999999999999999999999999 | bc
9999999999999999999999999999999999999999999999999999999999999999999999999999999
改行されません!思ったとおりに動くと楽しいですね!
ではこれで最初の「コラッツの問題」をやってみましょう!!
$ export BC_LINE_LENGTH=999
$ sh collatz.sh 99999999999999999999999999999999999999999999999999999999999999996
・・・(省略
24921477006304688
12460738503152344
collatz.sh: line 6: [: -eq: unary operator expected
Segmentation fault: 11
エラーで落ちました。
「Segmentation fault: 11」はセグメンテーション違反というアクセスしてはいけないメモリにアクセスした時に起きるエラーのようです。
再帰処理だし、桁数多いからメモリ使うだろうしで、これはどうしようもないかもしれないですね(^_^;)
(再帰じゃなくてwhileで回す処理ならメモリ食わないのかな?とか考え中。)