LoginSignup
6
4

More than 5 years have passed since last update.

bcコマンドの限界は68桁?(回避方法あり

Last updated at Posted at 2015-05-08

hello worldより「コラッツの問題」書くほうがいろいろ学べそうという投稿でシェルスクリプトでコラッツの問題を書きました。

collatz.sh
#!/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で回す処理ならメモリ食わないのかな?とか考え中。)

6
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4