Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした