コンテンツにスキップ

bc (UNIX)

出典: フリー百科事典『ウィキペディア(Wikipedia)』

bc(ビーシー)は、Unixで広く使われている、中置記法の算術式を計算する任意精度演算プログラムおよびその入力言語である。式はコマンドライン引数として与えることもできるし、標準入力などから与えることもできる。例えば、(1 + 3) * 2 を入力すれば 8 と出力する。

POSIXで標準化されている[1]が、これを大幅に拡張したGNU版の実装もある。Plan 9版は、標準のスーパーセットでGNU版のサブセットになっている。そのほか、オリジナルのUNIX版の実装[2]や、OpenBSDプロジェクトで実装されたもの(他にFreeBSDなどで使われている)が主要な実装である。

Windows用などのバイナリが配布されているものもある。

標準

[編集]

bcは伝統的に、後置記法(逆ポーランド記法)のdcというプログラムのフロントエンドプロセスとして実装されてきた。標準も、それに倣った実装を考慮して定義されているが、必ずそのように実装しなければならない、とはしていない。後述するGNU版ではbcとdcはそれぞれ別のプログラムとして実装されている。bcをdcと連携させる実装において、bcとdcのどちら側を親プロセスとするかは実装によって異なる。

言語要素には、1文字の変数名・配列名・関数名、ほとんどの標準的演算子、よくある制御構造としてC言語にあるもの(if文、whileループ、forループ)が備わっている。なお、C言語とは異なり、if文にはelse節がない。

関数の定義にはキーワード define を使い、関数の返す値は return の後の括弧内にその値を記述する。関数内で変数が局所変数であることを示すため、auto というキーワードを使って変数を宣言する(C言語ではオプション)。

全ての数と変数の中身は任意精度数であり、その精度(十進での桁数)は大域変数 scale で決まる。

対話型モードでの入力と出力やプログラム内の定数の底(基数)は、予約された変数 ibase (入力)と obase (出力)で指定できる。

計算結果を変数に格納しないと、そのまま出力として結果が表示される。 BASIC言語のような対話型での利用を想定されているため、文の終わりは改行(LF)が必要。セミコロン ; などをつけると文法エラーとなる。

コメントは、C言語と同様に /**/ で囲む。

演算子

[編集]

C言語と同じ演算子

[編集]

以下の演算子は、C言語と同じ作用をする。

  • "+"、"-"、"*"、"/"、"+="、"-="、"*="、"/="、"++"、"--"、"<"、">"、"=="、"!="、"<="、">="、"("、")"、"["、"]"、"{"、"}"

C言語と類似する演算子

[編集]

剰余演算子

  • "%"、"%="

は、大域変数 scale が0に設定されているときだけC言語と同じ作用となる。すなわち、精度が0とは整数のみの計算を行うことを意味する。scale が0より大きい場合、商を指定された精度で計算したものに除数をかけて、それを被除数から引いた値となる(ほとんどゼロに近い)。

C言語と意味が異なる演算子

[編集]

"^" や "^=" という演算子は、C言語ではビット単位の排他的論理和だが、bcではべき乗演算子(ただし、べき指数は整数)である。

C言語にあるがbcにない演算子

[編集]

次の、ビット演算子、ブーリアン演算子、比較演算子などは、標準には存在しない。

  • "&"、"|"、"^"、"&="、"|="、"^="
  • "&&"、"||"、"^^"、"&&="、"||="、"^^="
  • "<<"、">>"、"<<="、">>="、"?:"

組み込み関数

[編集]

標準では唯一の組み込み関数として sqrt() がある。他の関数は外部の標準ライブラリの形で提供される。

数学関数

[編集]

-l オプションで追加される数学関数には、三角関数(正弦、余弦、逆正接)、自然対数指数関数、2引数のベッセル関数 J が含まれる。ほとんどの標準的関数(逆正弦関数や逆余弦関数など)は、これらを使って構築できる。他の関数の実装については、外部リンクを参照。

なお、-l オプションでは、それと同時に、scaleが20に設定される。そのため剰余演算が思わぬ結果を返すことがある。例えば、"bc -l" として、"print 3%2" と入力すると、1ではなく0と出力する。しかし、"bc -l" で起動した後で "scale=0" とすれば、"print 3%2" は1を出力する。

Plan 9版

[編集]

Plan 9版は標準とほぼ同じだが、print 文が追加されている。

GNU版

[編集]

GNU版では数々の拡張を加えられている。また、dcのフロントエンドではなく、独立したプロセスとして動作する実装である。しかし、標準とは互換性を保っており、標準bc用プログラムは修正なしでGNU版でも実行できる。

変数、配列、関数の名前は1文字に制限されない。また、C言語の演算子もさらに導入されていて、特にif文にはelse節を書くことができる。

出力は、標準と同様に計算結果を変数に代入しないときにも表示されるし、print 文で表示させることもできる。

さらに、read 文でプログラムに対話的に数値を入力することもできる。

C言語風のコメント以外に、# から行末までをコメントとして扱う。

直近の計算結果は常に組み込み変数 last に格納されている。

追加された演算子

[編集]

以下の論理演算子が追加されている。

  • &&
  • ||
  • !

これらは if 文の条件節などで使える。なお、ビット演算や代入と組み合わせた演算はやはり存在しない。

関数

[編集]

関数については、標準と同じである。

コード例

[編集]

bcの ^ 演算子はべき指数が整数でないと機能しない。bcの利用者がまず書こうとする関数の1つとして、浮動小数点数のべき指数を扱えるべき乗関数が考えられる。次の2つのコード例は、-l オプションによる数学関数を使うことを前提としている。

標準の bc によるべき乗関数

[編集]
/* x の整数部分を返す関数 */
define i(x) {
   auto s
   s = scale
   scale = 0
    x /= 1   /* x を丸める */
   scale = s
   return (x)
}
/* x^y == e^(y*log(x)) という性質を使う */
define p(x,y) {
   if (y == i(y)) {
      return (x ^ y)
   }
   return ( e( y * l(x) ) )
}

GNU版のbcによる同等のべき乗関数

[編集]
# 数の整数部分を返す関数
define int(number) {
   auto oldscale
   oldscale = scale
   scale = 0
   number /= 1 /* 丸める */
   scale = oldscale
   return number
}

# number^exponent == e^(exponent*log(number)) という性質を利用
define power(number,exponent) {
   if (exponent == int(exponent)) {
      return number ^ exponent 
   } else {
      return e( exponent * l(number) )
   }
}

円周率を1万桁まで計算する(高野の公式(1982年)を使用)

[編集]

(「高野の公式」を参照)

$ bc -l -q
scale = 10000;
(12*a(1/49)+32*a(1/57)-5*a(1/239)+12*a(1/110443))*4

C言語の関数をbcに変換する

[編集]

bc の文法はC言語とよく似ているので、Cで書かれたアルゴリズムは容易に bc に翻訳可能であり、それによって bc の任意精度の恩恵を受けることができる。例えば、Journal of Statistical Software (July 2004, Volume 11, Issue 5) には、George Marsaglia の論文に累積正規分布に関する次のC言語コードが掲載されていた。

double Phi(double x)
{
    long double s=x,t=0,b=x,q=x*x,i=1;
    while(s!=t)
        s=(t=s)+(b*=q/(i+=2));
    return .5+s*exp(-.5*q-.91893853320467274178L);
}

これは簡単にGNU bc用に書き換えることができ、次のようになる。

define normal(x)
  {
     auto s,t,b,q,i,const;
     const=0.5*l(8*a(1));
     s=x;
     t=0;
     b=x;
     q=x*x;
     i=1;
     while(s!=t) {s=(t=s)+(b*=q/(i+=2))};
     return .5+s*e(-.5*q-const);
  }

シェルスクリプトでのbcの利用

[編集]

bcは非対話的に使うこともでき、入力はパイプで供給する。シェルスクリプトで使う場合に便利である。例えば、

 $ result=$(echo "scale=2; 5 * 7 / 3;" | bc)
 $ echo $result
 11.66

あるいは、入力はヒアドキュメントでも構わない。

 $ bc <<!
 scale=2
 5 * 7 / 3
 !
 11.66

その他

[編集]

数値の指数表記(たとえば 1.23e-17 のように定数を記述したり、入出力をする機能)は備わっていない。

脚注・出典

[編集]

参考文献

[編集]

外部リンク

[編集]