bc(1)

名称
bc - 任意の精度の計算言語

書式
bc [ -lws ] [ file ... ]

バージョン
このマニュアルは GNU bc version 1.03 について記述してあります。

解説
bc は、任意の精度の数字を扱う事ができ、プログラミング言語 C の文法に よく似た形の入力をインタラクティブに実行する言語です。 コマンドラインのオプションの指定により、標準数式ライブラリを使用することも できます。これを指定した場合は、どのファイルを処理するよりも前に 数式ライブラリが定義されます。 bc は動作を開始するとまず最初にコマンドラインで指定したファイルを 順に処理します。全てのファイルを処理した後は、bc は 標準入力からの読込みを行います。全てのコードは、それが読み込ま れた時点で実行されていきます。(もし、ファイル中にプロセッサを止める コマンドが含まれていた場合は、標準入力からの読込みは行われません。)

本バージョンの bc は、伝統的な bc のインプリメントおよび POSIX のドラフトよりも拡張されています。コマンドラインオプションにより、 これらの拡張に対して警告を表示したり拒絶したりすることが可能です。 拡張はそういうものとして扱われます。

  オプション

-l  標準数式ライブラリを定義します。

-w  POSIX bc に対する拡張機能が入力された場合は警告を出します。

-s  POSIX bc の言語仕様に従って、厳密に処理します。

  数
bc における最も基本的な要素は `数' です。数は、整数部と小数部があり、 任意の精度をとることができます。全ての数は、内部では 10 進数で表現されており、 計算も 10 進数で行われます (本バージョンでは、除算と乗算で結果に切捨てが 起こります)。数には length と scale という 2 つの属性があります。 length は 10 進での有効桁数で、 scale は小数点以下の 10 進での有効桁数です。 例えば、
    1935.000 は、lengthが 7 で、scale が 3 です。

  変数
数は、単純変数と配列の 2 種類の変数に保存されます。単純変数と配列変数には共に 名前が付けられます。この名前は、最初の 1 文字目がアルファベットで、後は、 アルファベット、数字およびアンダスコアを任意の文字数組み合わせて 使う事ができます。全てのアルファベットは小文字でなければなりません (アルファベットと数値を使った名前の機能は拡張機能です。 POSIX bc では、変数に英小文字 1 文字しか許されません)。 配列変数の名前には必ずブラケット ([]) がつくので、変数の型は文脈において はっきりしています。

特殊な変数として scale, ibase, obase, last の 4 つの変数があります。 scale で計算時の小数点以下の有効桁数を指定します。 scale のデフォルトは 0 です。 ibase と obase で入力および出力の基数を指定します。 デフォルトでは、入力、出力の基数は共に 10 です。 last は、最後に bc が出力した数を保持しています (これは拡張機能です)。これらについては、後で適切なところで詳しく説明します。 これらの変数には、式で使われる代入と同様の代入を行うことが可能です。

  コメント
bc は、/* から */ の間をコメントとして扱います。 コメントはどこから始まっていてもよく、1 文字の空白として扱われます (これにより、コメントはその前後の入力アイテムを切り離します。たとえば、 変数名の途中にコメントを置くことはできません)。 コメントの中にはいくつ改行があってもかまいません。

  式
`数' は、式および文によって操作されます。 言語はインタラクティブになるように設計されているため、 文および式は即座に実行されます。 "main" プログラムといったものはなく、そのかわり、コードは それに出くわした時点で実行されます。 (後で述べる`関数'は、それに出くわした時点で定義されます。)

式の最も単純なものは、ただの定数です。bc は、入力された 定数を、変数 ibase で指定される現在の基数を元に、内部的には 10 進表現の 数に変換します (関数の場合は例外です)。 ibase には、2 (2 進数) から 16 (F) までが使用できます。 数の入力には、0-9 および A-F の文字が利用できます (注意: これは大文字でなければなりません。小文字は変数です)。 1 桁の数は ibase の値に関係なくその値を持ちます (すなわち A=10)。 複数桁の数の場合、bc は ibase 以上の値をもつ全ての入力桁を ibase-1に変更します。これにより、数 FFF は、 その入力基数を使って 3 桁で表現可能な最大の値を常に表します。

全ての演算式が、他の多くの高級言語に似たものとなっています。 数の型は 1 種類しかないため、型変換の規則はありません。 そのかわり、式の有効桁数に関する規則があります。 全ての式に有効桁数があり、これはその命令が実行する元の数値の有効桁数と 変数 scale から決定されます。scale には、0 から C の整数で表現できる最大の値までが指定可能です。

以下、bc で使用可能な演算子を説明します。なお、完全形の式を "expr"、 単純変数または配列変数を "var" と表記します。 単純変数は単に
    name
と表し、配列変数は
    name[expr]
と表します。特に言及しない限り、結果の有効桁数は、注目している式の 最大有効桁数になります。

- expr
    結果はその式の符号を反転したものとなります。

++ var
    変数を 1 だけインクリメントし、その新しい値が式の結果となります。

-- var
    変数を 1 だけデクリメントし、その新しい値が式の結果となります。

var ++
    式の結果はその変数の値となり、それからその変数を 1 だけ インクリメントします。

var --
    式の結果はその変数の値となり、それからその変数を 1 だけ デクリメントします。

expr + expr
    式の結果は 2 つの式の和となります。

expr - expr
    式の結果は 2 つの式の差となります。

expr * expr
    式の結果は 2 つの式の積となります。

expr / expr
    式の結果は 2 つの式の商となります。結果の scale は変数 scale の値 となります。

expr % expr
    結果は、以下のようにして求められる剰余です。a%b を求めるために、まず a/b を scale の有効桁数で計算します。この結果を用いて、a-(a/b)*b を、 scale+scale(b) と scale(a) の大きい方の有効桁数で計算します。 もし、scale に 0 がセットされ、両方の式が整数であれば、整数の剰余 が求められます。

expr ^ expr
    式の結果は、1 番目の式の値を 2 番目の回数だけ乗じたものになります。 2 番目の式は、整数でなければなりません。 (2 番目の式が整数でない場合は、警告が表示され、 整数に切り詰めた値が使用されます。) 結果の scale は、べき指数が 負なら scale になります。べき指数が正なら、 "1 番目の式の scale とべき指数との積" および "scale と 1 番目の式の scale の大きい方" のうちの小さい方 (つまり、min(scale(expr1)*expr2, max(scale, scale(expr1)))) となります。 expr^0 は常に 1 を返します。

( expr )
    標準の優先度を使わずに、この式の評価を優先します。

var = expr
    式の値が変数に代入されます。

var <op>= expr
    "var" が 1 度しか評価されないこと以外は "var = var <op> expr" と同じです。 "var" が配列の場合は動作が違うことがあり得ます。

関係演算は、特殊な演算で、結果は常に 0 か 1 になります。関係が偽の時 0、真 の時 1 になります。関係演算は、演算式のどこでも使う事ができます。(これ は拡張機能です。POSIX bcでは、関係演算は、if, while, for 文の中だけで、 1 つの関係式しか使用できません。)

expr1 < expr2
    expr1 が expr2 より小さい場合 1 になります。

expr1 <= expr2
    expr1 が expr2 より小さいか等しい場合 1 になります。

expr1 > expr2
    expr1 が expr2 より大きい場合 1 になります。

expr1 >= expr2
    expr1 が expr2 より大きいか等しい場合 1 になります。

expr1 == expr2
    expr1 と expr2 が等しい場合 1 になります。

expr1 != expr2
    expr1 と expr2 が等しくない場合 1 になります。

論理演算も関係演算と同様、偽と真を表わす 0 と 1 の 2 つの値だけを取る 演算です。(これは拡張機能です。POSIX bc では、論理演算はありません)

!expr
    expr が 0 なら 1 になります。

expr && expr
    expr1 と expr2 が、両方とも 0 でないなら、1 になります。

expr || expr
    expr1 と expr2 のどちらか一方が 0 でないなら、1 になります。

各演算子の優先順位と結合規則は次の通りです。(最初のものほど低く、後にいくほど 高い優先順位で、先に実行されます。)
    || operator, left associative
    && operator, left associative
    ! operator, nonassociative
    Relational operators, left associative
    Assignment operator, right associative
    + and - operators, left associative
    *, / and % operators, left associative
    ^ operator, right associative
    - (単項マイナス), nonassociative
    ++ and -- operators, nonassociative

この優先順位は、POSIX bc のプログラムがそのまま正しく動くよう に配慮して決められています。このため、関係演算と論理演算 が、代入演算よりも下位に位置付けられており、C 言語のプ ログラムなどとは異なった動作となっています。例えば、次の 式の場合、
    a = 3 < 5

ほとんどの C 言語プログラマがそれが当然であると思う通りに、 ``3 < 5'' の関係演算が実行され、結果として真を表わ す 1 が変数 ``a'' に代入されます。これに対し、bc では、``a = 3'' の代入演算が先に実行され、代入結果としての ``3'' と ``5'' が比較されます。この間違いを避けるために、関係演算 と論理演算には、括弧を使うのが最良です。

bc では、ユーザー定義の関数と標準関数を使用することができます。これらの関 数は、C 言語などの関数と同様、"name(parameters)" の形で 演算式の中に使用できます。標準関数には、次のようなものがあります。

length ( expression )
    expression の有効桁数を返す。なお bc の内部表現は 10 進数なの で、有効桁数は、obase にかかわらず、10 進で表わした場合 の桁数で返される。

read ( )
    標準入力から数を入力して値とする。bcは、逐次処 理なので、read() が演算式に使われた時点で、標準入力を読 み出す。このため、データとプログラムの両方を標準入力か ら与えるような場合には、問題があることに注意する必要が ある。このため、ユーザからデータの入力の必要があるプ ログラムはあらかじめ作っておいてファイルから読み込ませ、 標準入力からプログラムを入力しないようにするのが最良で ある。

scale ( expression )
    expression の小数点以下の有効桁数を返す。なお bc の内部表現は 10 進数なの で、有効桁数は、obase にかかわらず、10 進で表わした場合 の桁数で返される。

sqrt ( expression )
    expression の平方根を返す。expression に負の値を指定した場合 は、ランタイムエラーになる。

  文
文は、処理を順番に実行していく単位です。bc は、プログラムを蓄え てから実行するのではなく、逐次的に実行していくために、改行が入 力された時点で、実行可能な文が存在していれば、即座に実行します。 このため、bc では改行が文の区切になっています。この他、セミコロン も文の区切として使用できます。改行が文の区切であるため、 不適当な場所で改行を入力すると、シンタックスエラーになります。 ただし、行末にバックスラッシュを入れて改行すると、bc は、文の区 切ではなく、単なる空白として処理します。 以下、bcの文法について説明します。(なお、以下の説明で、([]) で括っ た所は省略可能な項です。)

演算式 bc にとって、演算式には次の 2 つの種類があります。 1 つは、"<variable> <assignment> ..." で始まるの変数への代入で、もう 1 つは単なる ``expr'' による演算です。後者の場合、bc は、 expr を実行した後、結果を表示して改行します。 なお、"a=1" は代入とみなされるため結果は表示されませんが、 "(a=1)" は代入演算結果としての ``1'' が表示されます。 最後に表示 された値は、変数 last に蓄えられるので、直前の演算結果を 次に使う場合には、表示された値をタイプし直す手間を省く ことができます。 結果の表示は、obase で指定した基数を元に行われます。 obase は、2 から 999 (現在のインプリメントの制限) で決め られる値まで指定することができます。なお、obase が 2 から 16 までは、`0' から `9' および `A' から `F' で表示しますが、16 以上 は、1 桁を数文字使い、各桁ごとに空白を入れて表示します。 例えば、obase が 32 の時、10 進数の 33 は、以下のように表示されます。
    01 01

文字列 bc は、ダブルクォート (") で囲まれた部分を、文字 列として、そのまま表示します。

print list
    print 文 (これは拡張機能です) は、list で指定さ れた内容を表示するものです。list には、文字列、演算式な どを、コンマで区切って指定し、print は、その順番に表示 を行い、最後は改行しないで終わります。 なお、print 文の list で指定する文字列には、特別にバックスラッシュ (\) で 始まる次の特殊文字を使用することができます。 bc が解釈できる特殊文字は、"a" (ベル)、"b" (バックスペース)、 "f" (フォームフィード)、"n" (改行)、"r" (復帰)、"q" (ダブルクォート)、 "t" (タブ)、"\" (バックスラッシュ) です。これ以外は無視されます。

{ statement_list }
    複数の文を 1 つのグループにまとめます。

if ( expression ) then statement1 [else statement2]
    expression の結果が 0 でないなら statement1 を実行します。 statement2 が存在し、expression の結果が 0 のときは、statement2 が 実行されます。(else 部分は拡張機能です)

while ( expression ) statement
    expression が0でない間、繰り返し statement を実行します。 expression は、毎回、statement を実行する前に実行されます。なお、 statement の中で、break 文が実行された場合は、while 文の繰り返しは中断されます。

for ( [expression1] ; [expression2] ; [expression3] ) statement
    expression1 は、最初に 1 回実行されます。expression2 は、statement を 実行する前に実行され、expression2 が 0 でない間、繰り返し statement を実行します。expression3 は、毎回 statement 実行後に 実行されます。 各 expression は省略可能で、expression2 が省略された場合は、常に 1 と みなして、無限ループになります。(expression が省略可能なのは拡張機能です。 POSIX bc では、3 つの expression はどれも省略できません) 以下は for 文と等価なコードです。
    expression1;
    while (expression2) {
       statement;
       expression3;
    }

break
    最も近い while もしくは for 文による繰り返しを強制的に中断します。

continue
    最も近い for 文による繰り返しで、最初の文に戻って実行を続けます。 (continue文は拡張機能です)

halt
    bc を終了します。 (halt 文は拡張機能です)

return
    関数から戻ります。関数の結果は 0 になります。

return ( expression )
    関数から戻ります。関数の結果は expression になります。

  疑似文
これは、今までの文とは動作が異なり、 ``compile'' (疑似文が 入力され内部で処理される時) 時点で実行されます。

limits
    bc のローカルバージョンにより制限されるもの を表示します。(limitsは拡張機能です)

quit
    bc を終了します。どんな場所にあっても、quit 文は 入力された時点で実行されます。例えば、 "if (0 == 1) quit" という記述であっても、bc は終了します。

warranty
    保証に関する注意を長めに表示します。 (warranty は拡張機能です)

  関数
関数は、後で実行されるべき計算手順を定義する機能です。関数は、 戻り値を計算して、呼びだし側に返します。関数は、それが入力から 読み込まれた時点で定義が行われる ``dynamic'' (動的) 割り当て です。 一度定義された関数は、同じ名前で別の関数が定義されるまで使用可能で、 新しい関数が定義された場合は、前の関数に置き換えられます。 関数の定義は、以下のように行います。
    define name ( parameters ) { newline
        auto_list   statement_list }
name は関数名で、ここで定義した関数の呼び出しは、演算式の中で "name(parameters)" の形式で書くことで、呼び出されます。

parameterは、関数に与える引数を受けとる変数です。関数定義では、 0 個以上の変数名を、各々コンマで区切って並べることで指定します。 配列を引数として受けとる場合 (配列を使えるのは拡張機能です) は、 "name[]" の形で指定します。配列でない通常の数の場合、パラメータ の値は、``call by value'' の方式により渡され、配列の場合は、 ``call by variable'' の方式になります。 関数定義が動的に行われるために、引数の数やタイプは、関数の定 義時でなく、関数が呼び出される時にチェックされ、もし、ミスマッチがあった時は、 ランタイムエラーになります。未定義の関数を呼び 出そうとした時も、ラインタイムエラーになります。

auto_list は省略可能で、ローカル変数として使用する変数のリストです。 ローカル変数を使用する場合は、次のように指定します。

"auto name , ... ;"

配列も使用可能です。引数およびローカル変数は、スタック上に確保 され、関数が実行される前に引数の値やローカル変数なら 0 に初期化 されます。実行後、スタックがポップされることで、以前の値に戻されます。 これにより、関数の再帰呼びだしが可能となっています。

bc のローカル変数は、伝統的な意味でのローカル変数とは多少違い、 例えば、関数 A が関数 B を呼び出しているような場合、関数Bの中に関数 A の ローカル変数と同じ名前のローカル変数がない限り、そのまま、 関数Aのローカル変数名を使って、値を参照することができます。

statement_list は、関数の本体で、bc の文をセミコロンもしくは改行で 区切って並べたものです。関数から戻るには、return 文を使い ます。もし、return文が無かった場合は、statement_listの最後に、 "return (0)" があるものとみなします。

関数の中では、変数 ibase の動作が変わります。関数の中で使われて いる定数は、関数の呼びだし時点の ibase を元に変換が行われます。 このため、関数内部で ibase を変更しても無視されます。ただし、標 準関数 read を呼び出した場合は例外で、これは常に現在の ibase の値をもとに変換が行われます。

  数学ライブラリ
bc に、-l オプションを付けて起動した場合は、数学ライブラリ が読み込まれ、デフォルトの scale が 20 に設定されます。数学ライブラリ によって使用可能になる関数は、次の通りです。

s (x)
    sin (x の単位はラジアン)

c (x)
    cos

a (x)
    atan

l (x)
    log (自然対数)

e (x)
    exp

j (n,x)
    ベッセル関数

  使用例
次の例は、/bin/sh でシェル変数 pi に ``パイ'' の値を代入します。
    pi=$(echo "scale=10; 4*a(1)" | bc -l)

次の例は、数学ライブラリで使われている ``e (x)'' の定義です

    scale = 20
    /* Uses the fact that e^x = (e^(x/2))^2
       When x is small enough, we use the series:
         e^x = 1 + x + x^2/2! + x^3/3! + ...
    */
    define e(x) {
      auto  a, d, e, f, i, m, v, z
      /* Check the sign of x. */
      if (x<0) {
        m = 1
        x = -x
      }
      /* Precondition x. */
      z = scale;
      scale = 4 + z + .44*x;
      while (x > 1) {
        f += 1;
        x /= 2;
      }
      /* Initialize the variables. */
      v = 1+x
      a = x
      d = 1
      for (i=2; 1; i++) {
        e = (a *= x) / (d *= i)
        if (e == 0) {
          if (f>0) while (f--)  v = v*v;
          scale = z
          if (m) return (1/v);
          return (v/1);
        }
        v += e
      }
    }

次の例は、bc の拡張機能を使って、``checkbook balances'' (小切手帳残高) を計算するプログラムです。

    scale=2
    print "\nCheck book program!\n"
    print "  Remember, deposits are negative transactions.\n"
    print "  Exit by a 0 transaction.\n\n"
    print "Initial balance? "; bal = read()
    bal /= 1
    print "\n"
    while (1) {
      "current balance = "; bal
      "transaction? "; trans = read()
      if (trans == 0) break;
      bal -= trans
      bal /= 1
    }
    quit

次の例は、再帰呼び出しにより階乗を計算する関数です。

    define f (x) {
      if (x <= 1) return (1);
      return (f(x-1) * x);
    }

関連ファイル

/usr/local/lib/libmath.b
    ``-l'' オプションで読み込まれる数学ライブラリ

注意
本 bc は、 dc(1) を使用する伝統的なインプリメントではありません。 POSIX bc との相違点および各種の制限値については、オリジナルの GNU bc version 1.02 のマニュアルを参照してください。

バグ
エラーリカバリがまだうまくいっていません。

規格
POSIX P1003.2/D11 draft