bc - 任意精度の計算言語 |
bc [ -hlwsqv ] [long-options] [ file ... ] |
このマニュアルは GNU bc version 1.06 について記述してあります。 |
bc は、任意の精度の数値を扱う事ができ、プログラミング言語 C の文法によ く似た形の入力を対話的に実行する言語です。コマンドラインのオプション の 指 定により、標準数学ライブラリを使用することもできます。これを指定した 場合は、どのファイルを処理するよりも前に数学ライブラリが定義されま す。 bc は動作を開始するとまず最初にコマンドラインで指定したファイルを順に処 理します。すべてのファイルを処理した後は、bc は標準入力からの読み込みを 行 い ま す。すべてのコードは、それが読み込まれた時点で実行されていきま す。(もし、ファイル中にプロセッサを止めるコマンドが含まれていた場合は、 標準入力からの読み込みは行われません。) 本バージョンの bc は、伝統的な bc の実装および POSIX のドラフト規格より も拡張されています。コマンドラインオプションにより、これらの拡張に対 し て 警告を表示したり拒絶したりすることが可能です。本ドキュメントでは、こ のプロセッサが受理する言語について説明します。拡張機能についてはその 旨 明記します。 |
オプション |
-h, --help |
使用方法を表示し、終了します。 |
-i, --interactive |
対話モードを強制します。 |
-l, --mathlib |
標準数学ライブラリを定義します。 |
-w, --warn |
POSIX bc に対する拡張機能が入力された場合は警告を出します。 |
-s, --standard |
POSIX bc の言語仕様に厳密に従って処理します。 |
-q, --quiet |
GNU bc 導入メッセージを表示しません。 |
-v, --version |
バージョン番号と著作権を表示して終了します。 |
数 |
bc における最も基本的な要素は ‘数’ です。数は、整数部と小数部があり、任 意の精度をとることができます。すべての数は、内部では 10 進数で表現さ れ ており、計算も 10 進数で行われます。(本バージョンでは、除算と乗算で結果 に切捨てが起こります。) 数には length と scale という 2 つの属性があ り ま す。 length は 10 進での有効桁数で、scale は小数点以下の 10 進での有 効桁数です。例えば、 .000001 は、lengthが 6 で、scale も 6 です。 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 文字の空白として扱われます。 (これにより、コメント はその前後の入力アイテムを切り離します。たとえば、変数名の途中にコメ ン ト を置くことはできません。) コメントの中にはいくつ改行があってもかまい ません。 bc をスクリプトとしても使えるようにするため、1 行コメントが拡張機能とし て追加されました。1 行コメントは # で始まり、次の改行まで有効です。その 改行文字自体はコメントの一部とはみなされず、普通に処理されます。 |
式 |
‘数’ は、式および文によって操作されます。この言語は対話的になるように設 計 されているため、文および式は可能な限り即座に実行されます。 "main" プ ログラムといったものはなく、そのかわり、コードはそれに出くわした時点 で 実 行 さ れます。 (後で述べる‘関数’は、それに出くわした時点で定義されま す。) 式の最も単純なものは、ただの定数です。bc は、入力された定 数 を、 変 数 ibase で指定される現在の基数を元に、内部的には 10 進表現の数に変換しま す。(関数の場合には例外があります。) ibase には、2 から 16 までが使用で きます。この範囲を越える値を ibase に代入しようとすると、 2 あるいは 16 を指定したことになります。数の入力には、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 の大きい方" の う ち の 小 さ い 方 ( つ ま り、scale(a^b) = min(scale(a)*b, max( scale, scale(a)))) となり ます。 expr^0 は常に 1 を返します。 |
( expr ) |
標準の優先度を使わずに、この式の評価を優先します。 |
var = expr |
式の値が変数に代入されます。 |
var <op>= expr |
"var" が一度しか評価されないこと以外は "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 になります。 |
論理演算も使えます。(POSIX bc には論理演算はありません。) 論理演算も 関 係演算と同様、結果は 0 か 1 (各々偽および真) になります。論理演算子は以 下の通り。 |
!expr |
expr が 0 なら 1 になります。 |
expr && expr |
expr1 と expr2 が両方とも 0 でないなら、1 になります。 |
expr || expr |
expr1 と expr2 のどちらか一方が 0 でないなら、1 になります。 |
各演算子の優先順位と結合規則は次の通りです。 (最初のものほど低く、後 に いくほど高い優先順位で先に実行されます。) || (左から結合) && (左から結合) ! (結合せず) 関係演算 (左から結合) 代入演算 (右から結合) + - (左から結合) * / % (左から結合) ^ (右から結合) - (単項マイナス) (結合せず) ++ -- (結合せず) この優先順位は、POSIX bc のプログラムがそのまま正しく動くように配慮して 決められています。このため、関係演算と論理演算を代入文と共に用 い た 場 合、通常とは異なる振る舞いをします。次の例を考えてみましょう: |
a = 3 < 5 |
C プログラマのほとんどは、 ‘‘3 < 5’’ の関係演算が実行された結果 (つまり 1) が変数 ‘‘a’’ に代入される、と考えるでしょう。ところが bc では、ま ず 3 が変数 ‘‘a’’ に代入され、それから 3 と 5 の比較が行われるのです。この 間違いを避けるために、関係演算や論理演算を代入演算と共に用いる場合 は、 括弧を使うのが最良です。 bc には特別な式がさらにいくつか備わっています。それはユーザ定義関数と標 準関数に関するもので、すべて "name(parameters)" という形をしていま す。 ユー ザ定義関数については関数の章を参照して下さい。標準関数は以下の通り です: |
length ( expression ) |
expression の有効桁数を返します。 |
read ( ) |
(拡張機能) 関数の出現位置に関係なく、標準入力から数を読み取りま す。 デー タ とプログラムの両方を標準入力から与えるような場合に は、問題を生じうることに注意して下さい。最良の方法は、ユーザ か ら データの入力の必要があるなら、プログラムはあらかじめ作ってお き、標準入力からプログラムを入力しないようにすることです。 read 関 数の値は標準入力から読み込んだ数です。その際、変換基数として 変数 ibase の現在の値が用いられます。 |
scale ( expression ) |
expression の小数点以下の有効桁数を返します。 |
sqrt ( expression ) |
expression の平方根を返します。 expression に負の値を指定した場 合は、ランタイムエラーになります。 |
文 |
文は (ほとんどの算術言語がそうであるように)、処理を順番に実行していく単 位です。 bc では文は「できるだけ早い段階で」実行されます。改行が入力 さ れた時点で、実行可能な文が存在していれば、即座に実行します。このため bc では改行が重要な役割を持っています。実際、セミコロンと改行が文の区切 り と して使用されます。不適当な場所で改行を入力すると、文法エラーになりま す。改行は文の区切りですが、バックスラッシュを用いて改行を隠すことが で き ま す。 bc にとって、"\<nl>" (<nl>は改行) は改行ではなく空白に見えま す。文のリストは、セミコロンと改行で区切られた文の並びです。以下、bc の 文 の種類とその動作について説明します。 (なお、以下の説明で ([]) で括っ た部分は省略可能な項です。) |
演算式 |
演算式には次の 2 つの種 類 が あ り ま す。 演 算 式 が "<variable> <assignment> ..." で始まっていれば、それは代入文と して扱われます。そうでなければ、演算式は評価されて出力に表示 さ れ ま す。結果が表示された後、改行が表示されます。例えば、"a=1" は代入文であり、 "(a=1)" は代入文が埋め込まれた演算式です。表示 さ れ る 数 値はすべて、変数 obase で決まる基数で表示されます。 obase に指定できる値は 2 から BC_BASE_MAX までです。 (「制 限」 の章を参照。) 基数 2 から 16 まででは、通常の数表記法が用いられ ます。基数が 16 より大きい場合、bc は、各桁を 10 進表記する複数 桁 文字表記法で表示します。複数桁文字表記法では、各桁は空白で区 切られます。各桁は "obase-1" を 10 進で表記するのに必要な桁数の 数字から成ります。数の精度は任意に選べるため、数によっては 1 行 に表示できない場合もあります。そのような長い数は、行末に "\" を 付 けて次行に継続します。 1 行に表示できる文字数は 70 です。 bc の対話的性質により、ある数を表示すると、表示した値が特 殊 変 数 last に代入されるという副作用が生じます。ユーザはタイプし直すこ となく最後に表示された値を再利用できます。 last に値を代入す る こ とも可能で、その場合、前回表示された値が代入値で上書きされま す。新しく代入した値は、次に数が表示されるか別の値が last に 代 入 されるまで有効です。(bc の実装によっては、数の一部になってい ない単一のピリオド (.) を last の短縮表記として用いることができ ます。) |
|
string |
文字列 string が出力に表示されます。文字列は二重引用符 で始まり、次の二重引用符までのすべての文字を含みます。改行を 含 め、 すべての文字は文字通りに解釈されます。文字列の後に改行は出 力されません。 |
print list |
print 文 (これは拡張機能です) は、もうひとつの出力方 法 で す。 "list" はコンマで区切った文字列および演算式のリストであり、各文 字列あるいは演算式がリストの順に表示されます。最後に改行は出 力 さ れません。演算式は評価され、その値が表示されるとともに、変数 last に代入されます。 print 文中の文字列は出力に表示さ れ ま す が、 特殊文字を含めることができます。特殊文字はバックスラッシュ (\) で始まります。 bc で使える特殊文字は、 "a" ( ベ ル)、"b" ( バッ ク スペース)、 "f" (フォームフィード)、"n" (改行)、"r" (復 帰)、"q" (二重引用符)、 "t" (タブ)、"\" (バックスラッシュ) で す。これ以外は無視されます。 |
{ statement_list } |
複文です。複数の文を 1 つのグループにまとめて実行します。 |
if ( expression ) statement1 [else statement2] |
if 文は演算式 expression を評価し、その値に応じて文 statement1 または文 statement2 を実行します。 expression の値が 0 でなけれ ば statement1 が実行されます。 statement2 が存在し、expression の値が 0 ならば、statement2 が実行されます。 (else 節は拡張機能 です。) |
while ( expression ) statement |
while 文は expression が 0 でない間、繰り返し statement を実行 します。 statement の実行前に毎回 expression を評 価 し ま す。 expression の値が 0 になるか、break 文を実行すると、ループが終 了します。 |
for ( [expression1] ; [expression2] ; [expression3] ) statement |
for 文は statement の繰り返し実行を制御します。 expression1 は ルー プ実行の前に評価されます。 expression2 は statement の実行 前に毎回評価され、その値が 0 でなければ statement が実行され ま す。 expression2 の 値 が 0 になると、ループは終了します。各 statement 実行の後、再び expression2 が 評 価 さ れ る 前 に expression3 が評価されます。 expression1 あるいは expression3 が省略されていると、そこでは何も評価されません。 expression2 が 省 略 されている場合、expression2 が 1 であるのと同様に扱われま す。 (各 expression が省略可能なのは拡張機能です。 POSIX bc で は、3 つの expression はどれも省略できません。) 以下は for 文と 等価なコードです: expression1; while (expression2) { statement; expression3; } |
break |
それを含む最も内側の while もしくは for 文による繰り返し を強制的に中断します。 |
continue |
そ れ を 含 む最も内側の for 文における次の繰り返しに進みます。 (continue 文は拡張機能です) |
halt |
実行されると bc プロセッサを終了させます(拡張機能)。例 え ば "if (0 == 1) halt" の場合は bc は終了しません。 halt 文が実 行されないからです。 |
||
return |
関数から戻ります。関数の結果は 0 になります。(関数の 章 を参照) |
return ( expression ) |
関数から戻ります。関数の結果は expression になります。(関数の章 を参照) 拡張機能ですが、括弧は必須ではありません。 |
疑似文 |
これらは今までの文とは動作が異なります。疑似文は実行文ではなく、「コ ン パイル」時点で処理されます。 |
limits |
bc のローカルバージョンにより制限される限界値を表示しま す。 (limits は拡張機能です) |
||
quit |
bc を終了します。どんな場所にあっても、quit 文は入力さ れ た 時点で実行されます。例えば、 "if (0 == 1) quit" という記 述であっても、bc は終了します。 |
warranty |
保証に関する注意を長めに表示します。 (warranty は拡張機能です) |
関数 |
関数は、後で実行されるべき計算手順を定義する機能です。 bc の関数は常 に 値 を計算し、それを呼びだし側に返します。関数定義は、それが入力から読み 込まれた時点で定義が行われるという点で「ダイナミック(動的)」です。一 度 定 義された関数は、同じ名前で別の関数が定義されるまで使用可能で、新しい 関数が定義された場合は、前の関数が置き換えられます。関数の定義は、以 下 のように行います: define name ( parameters ) { newline auto_list statement_list } 関数呼び出しは、 "name(parameters)" という形式の演算式です。 パラメータ parameters は数あるいは配列 (拡張機能) です。関数定義では、0 あるいは 1 個以上のパラメータ名をコンマで区切って並べることで定義 し ま す。 数 は 値 渡 し(call by value)でのみ渡され、配列は変数渡し(call by variable)でのみ渡されます。配列はパラメータ定義中で "name[]" のように表 記 して指定します。関数呼び出しでは、数のパラメータに対して完全な演算式 の実パラメータを記述します。配列を渡す表記は配列パラメータ定義と同様 で す。 名前付き配列は変数(variable)によって関数に渡されます。関数定義はダ イナミックゆえ、パラメータの数と型は関数呼び出しの際にチェック さ れ ま す。 パラメータの数あるいは型に何らかの不整合があると、ランタイムエラー が発生します。未定義関数を呼び出した場合もランタイムエラーとなります。 auto_list は省略可能で、ローカル変数として使用する 変 数 の リ ス ト で す。auto_list が 存在するなら、その文法は "auto name, ... ;" となりま す。(セミコロンは省略可能です。) 各 name がローカル変数の名前とな り ま す。 配列はパラメータと同様の表記で指定できます。これらの変数は、関数の 最初でその値がスタックにプッシュされたのち値 0 に初期化され、関数の実行 中 に使用されます。これらの変数は関数出口にてポップされ、 (関数呼び出し 時の)元の値が復元されます。パラメータは実際にはローカル変数であり、関数 呼 び出しで与えられた値に初期化されます。 bc のローカル変数は伝統的な意 味でのローカル変数と異なり、関数 A が関数 B を呼び出しているよ う な 場 合、 関数 B の中に関数 A のローカル変数と同じ名前のローカル変数がない限 り、関数 A のローカル変数名をそのまま使って、関数 B から関数 A のローカ ル 変数をアクセスできます。ローカル変数とパラメータはスタックにプッシュ されるため、 bc は再帰的な関数呼び出しをサポートしています。 関数本体は bc の文のリストです。繰り返し述べますと、文はセミコロンか 改 行 で 区 切 ら れています。 return 文により関数は終了し、値を返します。 return 文には 2 つの形式があり、ひとつめの形式 "return" は、呼び出し 元 に 値 0 を 返 し ます。もうひとつの形式 "return ( expression )" は、 expression の値を計算し、それを呼び出し元に返します。各関数の最後 に は "return (0)" があるものと解釈されます。これにより、明示的に return 文を 置かなくても、関数は終了して値 0 を返します。 関数の中では、変数 ibase の動作が変わります。関数の中で使われている定数 は、関数の呼びだし時点の ibase を元に変換が行われます。このため、関数内 部で ibase を変更しても無視されます。ただし、標準関数 read を呼び出した 場合は例外で、これは常に現在の ibase の値をもとに変換が行われます。 拡 張 機 能ですが、定義の書式が若干緩やかになりました。標準では、開くブ レースが define キーワードと同じ行にあることと、他の部分が引き続く行 に あ ることが必須です。本バージョンの bc では、関数の開くブレースの前後の 改行数は任意です。例えば、次の定義は合法です。 define d (n) { return (2*n); } define d (n) { return (2*n); } |
数学ライブラリ |
bc に -l オプションを付けて起動した場合は、数学ライブラリが読み込まれ、 デフォルトの scale が 20 に設定されます。数学関数は、それを呼び出した時 点の scale の値に従って計算を行います。数学ライブラリによって使用可能に なる関数は、次の通りです: |
s (x) |
sin (x の単位はラジアン) |
|||
c (x) |
cos (x の単位はラジアン) |
|||
a (x) |
atan (返り値の単位はラジアン) |
|||
l (x) |
log (自然対数) |
|||
e (x) |
exp (指数関数) |
j (n,x) |
整数 n 次のベッセル関数 |
使用例 |
次の例は、/bin/sh でシェル変数 pi に ‘‘パイ’’ の値を代入します。 |
pi=$(echo "scale=10; 4*a(1)" | bc -l) |
次の例は、数学ライブラリで使われている ‘‘e (x)’’ の定義です。この関数は POSIX bc で記述されています。 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); } |
readline と libedit のオプション |
GNU bc は (configure のオプションによって) GNU readline 入力エディタ ラ イブラリまたは BSD libedit ライブラリを使うようにコンパイルできます。こ れは、bc に入力する前に、行の編集を可能にします。以前に入力した行のヒス ト リも利用可能になります。このオプションでコンパイルされた bc では、さ らに 1 つの特殊な変数 history が追加され、ヒストリに保存される行の数 を 指 定します。 readline では、その値が -1 (デフォルト値)なら、ヒストリ行 は制限なく保存されます。正の数を指定すると、ヒストリ行がその数に制限 さ れ ます。 0 ならヒストリ機能が無効になります。デフォルト値は 100 です。 詳しくは、ユーザマニュアルの GNU readline と history ライブラリ と BSD libedit をご覧下さい。 readline と libedit の両方を同時に有効化できませ ん。 |
相違点 |
このバージョンの bc は POSIX P1003.2/D11 ドラフトから実装されており、そ の ドラフトや以前の実装に比べていくつかの相違点や拡張点があります。伝統 的に行われていたような dc(1) を用いた実装ではありません。このバージョン は 単一プロセスであり、プログラムをバイトコードに変換したものを解析して 実行します。「ドキュメントに記載されていない」オプション (-c) があ り、 プ ログラムを実行する代わりに、それをバイトコードに変換した結果を標準出 力に出力します。これは主として、パーザのデバッグと数学ライブラリの準 備 に用いられました。 主 な相違点は拡張機能によるものです。機能を高めたり追加したりするために 機能が拡張されたり、新機能が追加されたりしています。相違点と拡張点の リ ストを以下に示します。 |
LANG 環境変数 |
このバージョンは、環境変数 LANG および LC_ で始まるすべての環境 変数の処理に関して POSIX 標準に準拠していません。 |