Bc (UNIX)
bc(ビーシー)は、Unixで広く使われている、中置記法の算術式を計算する任意精度演算プログラムおよびその入力言語である。式はコマンドライン引数として与えることもできるし、標準入力などから与えることもできる。例えば、(1 + 3) * 2 を入力すれば 8 と出力する。
POSIXで標準化されているが、これを大幅に拡張したGNU版の実装もある。Plan 9版は、標準のスーパーセットでGNU版のサブセットになっている。そのほか、オリジナルのUNIX版の実装や、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言語と同じ作用をする。
"+"、"-"、"*"、"/"、"+="、"-="、"*="、"/="、"++"、"--"、"<"、">"、"=="、"!="、"<="、">="、"("、")"、"["、"]"、"{"、"}"
"%"、"%="
は、大域変数 scale が0に設定されているときだけC言語と同じ作用となる。すなわち、精度が0とは整数のみの計算を行うことを意味する。scale が0より大きい場合、商を指定された精度で計算したものに除数をかけて、それを被除数から引いた値となる(ほとんどゼロに近い)。
"^" や "^=" という演算子は、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版は標準とほぼ同じだが、print 文が追加されている。
GNU版では数々の拡張を加えられている。また、dcのフロントエンドではなく、独立したプロセスとして動作する実装である。しかし、標準とは互換性を保っており、標準bc用プログラムは修正なしでGNU版でも実行できる。
変数、配列、関数の名前は1文字に制限されない。また、C言語の演算子もさらに導入されていて、特にif文にはelse節を書くことができる。
出力は、標準と同様に計算結果を変数に代入しないときにも表示されるし、print 文で表示させることもできる。
さらに、read 文でプログラムに対話的に数値を入力することもできる。
C言語風のコメント以外に、# から行末までをコメントとして扱う。
直近の計算結果は常に組み込み変数 last に格納されている。
以下の論理演算子が追加されている。
&&
||
!
これらは if 文の条件節などで使える。なお、ビット演算や代入と組み合わせた演算はやはり存在しない。
関数については、標準と同じである。
bcの ^ 演算子はべき指数が整数でないと機能しない。bcの利用者がまず書こうとする関数の1つとして、浮動小数点数のべき指数を扱えるべき乗関数が考えられる。次の2つのコード例は、-l オプションによる数学関数を使うことを前提としている。
/* 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) ) )
}
# 数の整数部分を返す関数
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) )
}
}
(「高野の公式」を参照)
$ bc -l -q
scale = 10000;
(12*a(1/49)+32*a(1/57)-5*a(1/239)+12*a(1/110443))*4
bc の文法はC言語とよく似ているので、Cで書かれたアルゴリズムは容易に bc に翻訳可能であり、それによって bc の任意精度の恩恵を受けることができる。例えば、Journal of Statistical Software (July 2004, Volume 11, Issue 5) には、George Marsaglia の論文に累積正規分布に関する次のC言語コードが掲載されていた。
これは簡単にGNU 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 のように定数を記述したり、入出力をする機能)は備わっていない。