bc - 任意精度の算術計算言語を使用する

形式

bc [–i] [–l] [file]

説明

bc は、算術計算を任意の精度で実行できるプログラム言語です。これは、端末から命令を入力することによって、対話式に使用することができます。また、ファイルから取り出したプログラムを実行することもできます。

コマンド行に指定された file 引数は、bc 命令を含む テキスト・ファイルでなければなりません。 bc は、これらのファイルからの命令をコマンド行に現れる順序で実行し、その後で標準入力 (stdin) からの命令を実行します。 bc は、quit 命令を実行したとき、または 標準入力 (stdin) のファイルの終わりに達したときに 終了します。

bc は、単純ではあるが完全なプログラム言語であり、構文が C プログラミング 言語に似ています。bc の本バージョンは、多くのシステムで使用可能な 標準言語のスーパーセットです。これは、この言語をより柔軟性の高い、役に立つ言語にするための、多くの追加機能を持っています。このインプリメンテーション (実装) 独自の機能については、注意書きがしてあります。

入力は、変数に値を割り当て、あるいは計算を行う、一連の命令によって 構成されます。関数 と呼ばれるサブプログラムを定義することもできます。この関数は、1 つの値を計算するために一連の命令を実行します。

bc は、値を計算するすべての行の結果を表示しますが、それを変数に割り当てることはしません。例えば、次の命令
2+2
は、以下の表示をします。
4

デフォルトにより、bc は評価した命令の結果を表示したあとで改行します。bc はまた、最後に表示した値を特殊変数 . (ドット) に 保管するので、次の計算で それを使用することができます。

このコマンドに対する UNIX03 での変更の要約については、UNIX03 用に変更されたシェル・コマンドを参照してください。

オプション

bc は、以下のオプションをサポートします。
–i
bc を対話モードにして、プロンプトを表示します。このモードでは、bc: というプロンプトを表示して入力を待ちます。 さらに、異なった方法でエラーを処理します。通常は、bc が ファイルを処理中にエラーになったときには、インタープリターはエラー・メッセージを表示し、終了します。対話モードでは、インタープリターはメッセージを表示し、デバッグができるようにプロンプト・モードに戻ります。
–l
他の入力を処理する前に、標準数学関数のライブラリーをロードします。また、このライブラリーは scale を 20 に設定します。–l ライブラリー内の関数の説明については、組み込み関数を参照してください。

数は、任意の負 (-) 符号または任意の正 (+) 符号に続いてゼロまたはそれ以上の数字のシーケンス、続いて任意の小数点 (.)、続いてゼロまたはそれ以上の数字のシーケンスにより構成されます。有効な数字は、0 から 9、および A から F の 16 進数 です。大文字は、10 から 15 の値を表してい ます。小数点の前か後のいずれかに、少なくとも 1 つの数字がなければ なりません。そうでない場合は、bc は小数点 を (前述のように) 特殊変数 . と解釈します。

数の長さは任意であり、スペースが含まれていても構いません。以下は、入力基数が 10 のいくつかの有効な数の例です。
0    0.   .0   -3.14159   +09.    -12    1 000 000
以下は、入力基数が 16 (ibase=16) の いくつかの有効な数の例です。
0    FF    FF.3    -10.444   A1

詳細は、Bases を参照してください。

制約事項: 数値をコンマで区切ることはできません。1000000 または 1 000 000 と書くことはできますが、1,000,000 と書くとエラー・メッセージが出ます。

ID

ID には、任意の数の文字、数字、または下線 (_) 文字のシーケンスを含めることができますが、小文字で始めなければなりません。 ID 内では、スペースは認められません。

POSIX ロケールでは、現行のロケールのように、有効な ID には任意の数の文字、数字、または下線 (_) 文字のシーケンスを含めることができますが、小文字で始めなければなりません。

その他のロケールの場合は、そのロケールの文字マップが、どの文字が ID 内に有効であるかを決めます。ロケール間で ID を移植可能にしたい場合に は、POSIX 文字セットからの文字セットを使用してください。2 文字以上の長さの ID の使用は、このインプリメンテーションでの拡張です。 ID は、以下のように、変数、関数、または 配列の名前として使用されます。
  • 変数 は、1 つの数値を保持します。関数にとってローカルな変数は 、auto ステートメントを使用して宣言することができます (関数を参照)。他のすべての変数はグローバルであり、任意の関数の内部またはすべての関数の外部で使用することができます。グローバル変数は、宣言する必要はありません。bc は、必要に応じて変数を作成し、初期値をゼロとします。(特殊変数 . [ドット] もあることを忘れないでください。これには、最後の計算の結果が入っています。)
  • 関数 は、1 つの値を計算するための一連の命令です。関数名の後には、括弧で囲まれたゼロまたはそれ以上の値が常に続きます。例えば 、my_func(3.14159) のようになります。(関数を参照)。
  • 配列 は、値のリストです。リスト内の値は、その配列のエレメント と呼ばれます。これらのエレメントには、ゼロから始まる番号が付けられます。このような番号を、配列の添え字 または指標 と 呼びます。添え字は、常に配列の後の大括弧の中に入っています。例えば、a[0] は、 配列 a 内のエレメント・ゼロを指しています。配列の最初のエレメントは常に、 添え字 0 を持っています。 添え字の値が浮動小数点数の場合は、添え字を整数にするために、小数点以下の部分は破棄されます。例えば、以下の式はいずれも同じエレメントを指しています。
    a[3]   a[3.2]   a[3.999]

    bc 配列内のエレメントの最大数は、0 から {BC_DIM_MAX}-1 の範囲 (両端も含む) です。他の多くの言語と異なり、配列のサイズを宣言する必要はありません。エレメントは必要に応じて動的に作成され、初期値はゼロになります。

関数の名前の後には必ず括弧が続き、配列の名前の後には必ず大括弧が続くため 、bc は 3 つのタイプの名前 (変数名、関数名、および配列名) をすべて 区別することができます。したがって、同じ名前の変数、関数、および配列を使用することができます。例えば、foo は変数であり、foo() は関数、foo[ ] は配列となります。

組み込み変数

bc には多くの組み込み変数があり、インタープリターのさまざまな局面を制御するために使用されます。この後のトピックでこれらを説明します。

スケール

スケールの値 は、算術演算の場合の小数点以下の桁の数です。 例えば、スケールが 3 の場合、計算では 小数点以下の桁が少なくとも 3 桁になります。これは、
5 / 3
が、以下の値であることを意味しています。
1.666

–l が指定された場合、スケールは 20 に設定されます。それ以外の場合、デフォルトのスケールはゼロです。

変数 scale は、現行のスケール値を保持しています。スケールを変更するためには、次のように、scale に新しい値を割り当てます。
scale = 5

scale は通常の bc 変数と同じなので、bc の式の どこででも使用することができます。

計算結果の小数点以下の桁数は、スケールだけでなく、計算のオペランドの小数点以下の桁数によっても 影響されます。これについては、算術演算子を参照してください。

scale という関数もあります。これは、任意の式のスケールを判別するために使用することができます。例えば、scale(1.1234) は 4 という結果を戻します。これは、数 1.1234 のスケールです。scale 関数の結果は、常に整数です (すなわち、スケールは 0 です)。

scale の最大値は、構成変数 {BC_SCALE_MAX} によって与えられます。最小値は 0 です。

基数

bc では、異なる基数 (例えば、8 進数 (基数 8) または 16 進数 (基数 16)) で数を指定することができます。 1 つの基数で数を入力し、それを異なる基数で出力することができるので、別の基数に数を変換するという作業が簡単になります。bc は、組み込み変数 ibaseobase を使用して これを行います。

ibase は、入力する数のための基数です。その初期値は 10 (通常の 10 進数) です。入力する数に別の基数を使用するためには、次のように、ibase に整数を割り当てます。
ibase = 8
これは、今後入力する数はすべて基数 8 (8 進数) であることを意味します。 有効な最大の入力基数は 16、有効な最小の入力基数は 2 です。15 より大き い数字を表すメカニズムは用意されていないため、16 より大きい基数は本質 的に役に立ちません。基数が 10 より大きい場合は、大文字を数字として使用してください。例えば、基数 16 は数字 0 から 9、および A から F を使用します。数字は、ibase の設定にかかわらず、どの数ででも 使用できますが、基数がその数字より小さい場合には、ほとんど意味があり ません。これが役に立つ 1 つのケースは、入力基数を 10 にリセットする場合です。定数 A は、ibase が何に設定されていても 10 という 値を持っています。したがって、入力基数を 10 にリセットするためには、次のように入力してください。
ibase = A

obase は、数が出力されるときの基数です。その初期値は 10 (通常の 10 進数) です。出力基数を変更するためには、obase に適切な整数を 割り当ててください。

出力基数が 16 またはそれ以下の場合は、bc は数を通常の 10 進数字 または 16 進数字 (必要な場合) で表示します。出力基数は、16 より大きくすることもできます。この場合、各数字 は 10 進数値で出力され、数字は 1 桁のスペースで区切られます。例えば 、obase が 1000 の場合、10 進数 123 456 789 は 以下のように出力されます。
123 456 789

この場合、数字は 0 から 999 の 10 進数値です。その結果、出力されるすべての値は、1 つまたはそれ以上のチャンク (塊) (1 つのチャンクごとに 3 つの 数字) に分けられます。10 の大きな累乗を出力基数に使用すると、出力を欄に分けて並べることができます。例えば、100 000 はよい出力基数になります。これは、数がそれぞれ 5 桁のチャンクにグループ化されるからです。

長い数は、1 行当たり最大 70 文字で出力されます。 数がこれより長い場合、bc は、その行の末尾に円記号 (¥) を入れて、 数が次の行に続くことを示します。円記号 (¥) および改行文字は、70 文字の文字長の一部としてカウントされます。

入力および出力の基数に関係なく、内部の計算は 10 進で行われます。したがって、小数点の後の桁数は、数が 10 進形式で表されたときのスケールによって決められます。

obase の最大値は、構成変数 {BC_BASE_MAX} によって与えられます。

算術演算

bc では、多くの算術演算が提供されています。標準の算術の規則に従って、いくつかの演算は他の演算よりも先に行われます。例えば、演算を括弧でグループ化しない限り、乗算は加算よりも先に行われます。先に行われる演算は、後で行われる演算よりも より高い優先順位 を持っていると言われます。

また、演算は結合順序 も持っています。結合順序によって、同じ優先順位の一連の演算を評価する順序が決められます。いくつかの演算は左から右に評価され、他の演算は右から左に評価されます。次のリストは、bc の演算子を最も高い優先順位のものから 最も低いものへと順に示しています。
bc 演算子
結合順序
( )
左から右へ
Unary ++ --
該当しない
Unary - !
該当しない
^
右から左へ
* / %
左から右へ
+ -
左から右へ
= ^= *= /= %= +=
右から左へ
== <= >= != < >
なし
&&
左から右へ
||
左から右へ

bc の優先順位は、C と同じではありません。C では、割り当て演算子は最も低い優先順位を持っています。

以下のリストは、それぞれの演算が何を行うかを説明しています。説明の中で、A および B は、任意の数、変数、配列エレメント、またはその他の式のいずれでも構いません。V は、変数または配列エレメントでなければなりません。
(A)
A は、すべての演算を行う前に評価する必 要がある ことを示します。
-A
式の否定です。
!A
式の論理的補数です。A がゼロと評価された場合、!A1 となります。A がゼロ以外の場 合、!A はゼロとなります。この演算子は、このバージョンの bc に固有なものです。
++V
V の値に 1 を追加します。式の結果は、V の新しい値です。
- -V
V の値から 1 を減算します。式の結果は、V の新しい値です。
V++
V の値に 1 を加算しますが、式の結果は V の古い値です。
V- -
V の値から 1 を減算しますが、式の結果は V の古い値です。
A ^ B
AB 乗を計算します。B は整 数でなければなりません。A^B の結果のスケールは、次のようになります。
min(scale(A) * abs(B), max(scale, scale(A)))

ここで、min は一組の数の最小値を計算し、max は最大値を計算します。

A * B
A 掛ける B を計算します。結果のスケールは、次のようになります。
min(scale(A) + scale(B), max(scale, scale(A), scale(B)))
A / B
AB で割ります。結果のスケールは、scale の値です。
A % B
AB で割った場合の剰余を計算します。これは 2 段階で計算されます。まず、bc は現行のスケールで A/B を計算します。次に、以下の式で剰余を求めます。
A - (A / B) * B
スケールは、以下のようになります。
max(scale + scale(B), scale(A))
A + B
AB を加算します。結果のスケールは、2 つ のオペランドのスケールの最大値です。
A-B
A から B を減算します。結果のスケールは、2 つ のオペランドのスケールの最大値です。
したがって、a=1+(b=2) のような演算を書くことができます。 この演算では、括弧内の割り当ての値は 2 です。これは、その 値が b に割り当てられるからです。したがって、値 3a に割り当てられます。可能な割り当て演算子 は、次のとおりです。
V = B
B の値を V に割り当てます。
V ^= B
V=V^B と同等です。
V *= B
V=V*B と同等です。
V /= B
V=V/B と同等です。
V %= B
V=V%B と同等です。
V += B
V=V+B と同等です。
V -= B
V=V-B と同等です。

以下の演算子は、すべて割り当て 演算子です。これらはオブジェクトに値を割り当てます。割り当て演算は、値を持っています。その値は、割り当てられている値です。

以下の式は関係 と呼ばれ、その値は真 (1) または偽 (0) のいずれかです。このバージョンの bc では、関係演算子は、ifwhile、または for ステートメントの条件部分としてだけではなく、任意の式の中で使用することができます。これらの演算子は、C 言語の同等な演算子とまったく同じ働きをします。関係の結果は、関係が偽の場合には 0、関係が真の場合には 1 です。
A == B
AB に等しい場合、そしてその場合にのみ真です。
A <= B
AB より小さいか等しい場合、そしてその場合にのみ真です。
A >= B
AB より大きいか等しい場合、そしてその場合にのみ真です。
A != B
AB に等しくない場合、そしてその場合にのみ真です。
A < B
AB より小さい場合、そしてその場合にのみ真です。
A > B
AB より大きい場合、そしてその場合にのみ真です。
A && B
A が真 (ゼロ以外) であり、かつ B が真の場合、そしてその場合にのみ真です。A が真でない場合、式 B はまったく評価されません。
A || B
A が真であるか、または B が真の場合、真です。A が真である場合、式 B はまったく評価されません。

コメントおよび空白

コメント は、以下の形式です。
/* Any string */
コメントは、テキストの複数の行に拡張することができます。bc は、 コメントの初めに /* を検出すると、次の */ までのすべてをスキップします。コメントが持っている唯一の効力は、トークンの終わりを示すことです。このバージョンの bc では、拡張機能の一つとして、# 文字を 使用する追加のコメント規則を提供しています。# から行の終わりまでのすべてのテキストは、1 つのブランクとして扱われます。例えば、次のようになります。
2+2 # this is a comment
bc はフリー・フォーマットです。コードを読みやすくするために、ブランクや水平タブ文字を自由に挿入することができます。命令は、行の終わりで終わるものと想定されています。改行に続けなければならないような長い命令がある場合は、最初の行の最後の文字として円記号 (¥) を 入れ、2 番目の行に続けてください。例えば、次のようにします。
a = 2¥
 + 3
¥ は命令が次の行に続くことを示すので、これは以下と同等になります。
a = 2 + 3

命令

bc の命令は、計算を行う式、割り当て、機能の定義、または文です。命令が割り当てでない場合は、bc は計算を完了したときに 命令の結果を表示します。例えば、
3.14 * 23
と入力すると、bc は計算の結果を表示します。しかし、
a = 3.14 * 23

と入力すると、bc は何も表示しません。これは式が割り当てだからです。代入式の値を表示したい場合は、単に式を括弧で囲んでください。

以下のリストは、bc によって認識される命令の形式を 示しています。
expression
expression の値を計算します。
“string”
ストリング定数です。bc はこの形式のステートメントを検出すると、ストリングの内容を表示します。例えば、以下のとおりです。
"Hello world!"
は、bcHello world! と表示するように 指示しています。ストリングの後に改行文字は出力されません。これによって、以下のようなことができます。
foo = 15
"The value of foo is "; foo
この命令によって、bc は次のように表示します。
The value of foo is 15
statement ; statement …
同一行の上の一連の文です。bc では、セミコロン (;) と改行は同等です。これらは、両方とも文の終わりを示します。bc は、これらの文を左から右の順序で実行します。
{statement}
中括弧文です。中括弧は、以下のように、一連の文を 1 つのグループにするために使用されます。
{
  statement
  statement
     …
}

中括弧は、数行に分割された一連の文を グループにすることができます。中括弧は、通常、ifwhile のような 制御ステートメントと共に使用されます。

break
while または for ループの内部でのみ使用で きます。 break はループを終了させます。
for (initexp ; relation ; endexp) statement
は、以下と同等です。
initexp
while (relation) {
    statement
    endexp
}
ここで、initexp および endexp は式であり 、relation は関係です。例えば、以下のとおりです。
a = 0
for (i = 1; i <= 10; ++i) a += i

は、前記の while の例と同等です。規則: 括弧内の 3 つの項目は、すべて指定する必要があります。C と異なり 、bc ではこれらの式を省略することはできません。

if (relation)statement
与えられた relation が真であるかどうかをテストします。真である場合は、bcstatement を実行します。そうでない場合は、bcstatement をスキップして 次の命令に進みます。例えば、以下のとおりです。
if ((a%2) == 0) "a is even"

は、a が偶数の値である場合に a is even と 表示します。

if (relation) statement1 elsestatement2
単純な if ステートメントと同様です。relation が真の場合は statement1 を実行し、それ以外の場合は statement2 を実行します。これは、以下のように使用することができます。
if ((a%2) == 0) "a is even" else "a is odd"

“a is even” と else キーワードとの間に文分離文字はありません。これは C 言語と異なります。

以下は、別の例です。
if (a<10) {
        "a "
        "is "; "less than 10 "
        a
} else {
        "a is"
        " greater than 10 "
        a
}

規則: 中括弧は、if および else キーワードと 同じ行にある必要があります。これは、(relation) の直後に改行またはセミコロンがあると、文のボディがヌルであることを示すからです。bc プログラムによくあるエラーの原因は 、if ステートメントのボディ部分を別の行に入力することです。–i が使用された場合、インタープリターは、ボディ部分がヌルの if ステートメントを検出したときに、警告を表示します。

while (relation)statement
relation が真である限り、与えられた statement を 繰り返し実行します。例えば、以下のとおりです。
i = 1
a = 0
while (i <= 10) {    a += i
    ++i
}

は、1 から 10 の整数を加算し、結果を a に格納します。

bcwhile ループを検出したときに relation が真でなかった場合は 、bcstatement を実行しません。

print expression , expression …
引数の式の結果を表示します。通常、bc は扱った各式またはストリングの値を 表示します。したがって、プログラム内で出力をフォーマットすることが困難 になります。この ため、z/OS シェル・バージョンの bc には、print ステートメント があり、どのように表示するかを制御できます。この print により、ストリングと同じ行に いくつかの数字を表示できます。この文は、その引数をすべて 1 行に 表示します。隣り合った数の間には、スペースが 1 つ表示されます (しかし、数とストリングの間にはありません)。引数のない print ステートメントは、改行を表示します。 最後の引数がヌルである場合は、次の出力は同一行に続けられます。以下のいくつかの例は、print の使用方法を示しています。
/* basic print statement */
print "The square of ", 2, "is ", 2*2
The square of 2 is 4
/* inserts a space between adjacent numbers */
print 1,2,3
1 2 3
/* note - no spaces */
print 1,"",2,"",3
123
/* just print a blank line */
print
/* two statements with output on same line */
print 1,2,3, ; print 4, 5, 6
1 2 3 4 5 6
quit
bc を終了します。他のバージョンの bc では、インタープリターはこのトークンを読み取るとすぐに終了します。このバージョン の bc は、quit を実際の文として扱いますので、ループや関数などの中で使用することができます。
sh …
行を実行のためにシステム・コマンド・インタープリターに 送ることができます。例えば、次のようにします。
sh more <foo

このコマンドは、最初の非ブランク文字から行の終わりまでのすべてを、実行のためにコマンド・インタープリターに送ります。

void expression
expression の計算の結果を、表示する代わりに、廃棄すなわち “void” (無効) にします。この命令は、++ および -- 演算子を使用するとき、あるいは、関数は使用するが戻り値は使用しないときに、役に立ちます。例えば、以下のとおりです。
void foo++

foo を増やしますが、結果は表示しません。void ステートメントは、このバージョンの bc に固有なものです。

他のいくつかのタイプの文は、関数定義のみに関係しています。これらは、次のトピックで説明されています。

関数

関数は、引数の値に基づいて結果を計算するサブプログラム です。 例えば、次の関数は華氏で与えられた温度を摂氏に変換します。
define f_to_c(f) {
    return ((f-32) * 5 / 9)
}
これは、f という 1 つの引数を取る、f_to_c() という 名前の関数を定義しています。関数のボディ は、中括弧で囲まれています。 左中括弧は、define キーワードと同じ行になければなりません。関数本体は、関数の結果 を計算するための一連の文で構成されています。以下の形式の式
return (expression)

は、expression の値を関数の結果として戻します。expression の前後の括弧は任意です。

サブプログラムをアクティブ化するためには、関数呼び出し を使用します。これは、以下の形式です。
name(expression,expression,…)

ここで、name は関数の名前、expression は関数の引数の値です。 関数呼び出しは、他の式のどこででも使用することができます。関数呼び出しの値は、関数が戻す値です。例えば、前に説明した f_to_c() では 、f_to_c(41) の値は 5 です (これは、華氏 41 度が摂氏 5 度に等しいからです)。

関数定義の一般的な形式は、以下のとおりです。
define name(parameter,parameter,…) {
    auto local, local, …
    statement
    statement
         …
}
最初の行の各 parameter は、変数名または配列名です。配列名は、その後に大括弧を付けて示されます。例えば、cmpvec が 2 つのベクトルを比較する 関数である場合、関数定義は以下のように始めます。
define cmpvec(a[],b[]) {

パラメーターは、同じ名前の配列または変数と競合しません。例えば、関数の内部に a という名前のパラメーターがあり、外部に a という名前の変数がある場合、2 つは全く別のエンティティーとみなされます。変数に値を割り当ててもパラメーターは変更されません。逆も同様です。すべてのパラメーターは、値で渡されます。このことは、引数値のコピーが作成されて、仮パラメーターに 割り当てられることを意味します。 これは、配列にも適用されます。関数に配列を渡すと、配列全体からコピーが作成されますので、配列パラメーターに対して行われる変更は、元の配列に影響しません。

引数のない関数も可能です。この場合、次のように、define 行の括弧内には パラメーターがありません。
define f() {

auto ステートメントは、一連のローカル 変数を 宣言します。変数名または配列名が auto ステートメント内に現れた場合、これらの項目の現行値は保管され、項目はゼロに初期化されます。関数の実行中は、項目には新しい値が入ります。関数が終了したとき、項目の古い値が復元されます。

しかし、bc は動的スコープの規則に従い、字句スコープ規則を使用する C とは異なります。 詳細は、使用上の注意 を参照してくだ さい。

例えば、以下のとおりです。
define addarr(a[],l) {
    auto i, s
    for (i=0; i < l; ++i) s += a[i]
    return (s)
}
は、配列内のエレメントを加算する関数です。引数 l は、その配列内のエレメントの数です。 この関数は 2 つのローカル名 (i という名前の変数と s という名前の変数) を使用します。これらの変数は、関数 addarr にとっては「ローカル」であり、この関数の外部の (または他の関数内の) 同じ名前のオブジェクトとは無関係です。 auto ステートメントで指定されたオブジェクトは 、自動 と呼ばれます。自動オブジェクトは、関数が呼び出されるたびに 0 に 初期化されます。このように、合計 s は、この関数が呼び出されるたびにゼロに設定されます。ローカル配列を持つこともできます。これは、auto ステートメントの後に大括弧を付けて指定します。
define func_with_local_array() {
        auto local_array[];
        for(i=0; i<100; i++) local_array[i] = i*2
}

この例は、local_array と呼ばれるローカル配列を定義しています。ローカル配列は、最初はその中にエレメントがありません。

パラメーターでもなく、auto でも宣言されていないオブジェクトを関数が参照した場合は、オブジェクトは外部 であると想定されます。関 数の外部の関数または文は、外部オブジェクトを参照すること ができます。例えば、以下のとおりです。
define sum_c(a[ ],b[ ],l) {
    auto i
    for (i=0; i < l; ++i) c[i] = a[i] + b[i]
}

は、c と名付けられた外部配列を参照します。これは、他の 2 つの配列のエレメントごとの合計です。sum_c を呼び出す前に c が存在していなかった場合は、動的に作成されます。プログラムが sum_c 文を呼 び出した後は、プログラム内または関数内のステートメントは配列 c を 参照することができます。

関数には通常、return ステートメントが必要です。これは、以下の形式です。
return (expression)

引数 expression が評価され、関数の結果として使用されます。 式は単一の数値を持っていなければなりません。配列であってはなりません。

return ステートメントは、関数内に他にもまだステートメントが残っている場合でも関数を終了します。例えば、以下のとおりです。
define abs(i) {
    if (i < 0) return (-i)
    return (i)
}

は、引数の絶対値を戻す関数です。 i がゼロより小さい場合は、関数は最初の return を 採用し、それ以外の場合は 2 番目を採用します。

関数は、関数内の最後のステートメントを実行することによっても終了します。その場合は、関数の結果はゼロです。関数 sum_c は、return ステートメントのない 関数の例です。この関数は return ステートメントを必要としません。これは、その機能が外部配列 c を計算することであり、単一の値を計算することではないためです。最後に、関数からは戻りたいが、値を戻したくない場合は、return() または単に return とします。return ステートメントにパラメーターがない場合は、デフォルト値ゼロが戻されます。

組み込み関数

bc には、さまざまな演算を実行する多数の組み込み関数があります。 これらの関数は、ユーザー定義の関数に似ています。しかし、それらを自分で定義する必要はありません。それらはすでに設定されています。組み込み関数は、以下のとおりです。
length(expression)
expression 内の 10 進数字の桁数を計算します。これには、小数点の前および後の数字が含まれます。length() の結果は整数です。例えば、length(123.456)6 を戻します。
scale(expression)
expression のスケールを戻します。例えば、scale(123.456)3 を戻します。 scale() の結果は常に整数です。数の長さから数のスケールを減算すると、小数点の前の数字の数を判別することができます。
sqrt(expression)
expression の値の平方根を計算します。結果は、最小小数部で切り捨てられます (四捨五入されません)。結果のスケールは、expression のスケール、または scale() の値の大きい方になります。
コマンド行に –l が指定されている場合は、以下の関数を使用することができます。そうでない場合は、関数名は無視されます。各関数には 2 つの名前があります。完全名、および POSIX.2POSIX.2 との互換性のための単一文字の名前です。完全名は、標準 C math ライブラリーの同等な関数の名前と同じです。
arctan(expression) または a(expression)
expression の逆正接を計算し、角度をラジアンで戻します。この関数は、atan(expression) として呼び出すことも できます。
bessel(integer,expression) または j(integer,expression)
expression のベッセル関数を、階数を integer として、計算します。この関数は、jn(integer,expression) として 呼び出すこともできます。
cos(expression) または c(expression)
expression の余弦を計算します。ここで、expression はラジアンでの角度です。
exp(expression) または e(expression)
expression の指数 (すなわち、expression に対する e の べきの値) を計算します。
ln(expression) または l(expression)
expression の自然対数を計算します。この関数は、log(expression) として呼び出すことも できます。
sin(expression) または s(expression)
expression の正弦を計算します。ここで、expression はラジアンでの角度です。

これらの関数が返す結果の scale 値は、関数が呼び出された時点での scale 変数の値になります。これらの関数が実行を完了した後の scale 変数の値は、呼び出し時の値と同じ値になります。

  1. これは、購入にかかる売上税を計算する単純な例です。購入額は purchase で与えられ、売上税率 (パーセント) は tax で与えられます。
    define sales_tax(purchase,tax) {
        auto old_scale
        scale = 2
        tax = purchase*(tax/100)
        scale = old_scale
        return (tax)
    }
    例えば、以下のとおりです。
    sales_tax(23.99,6)

    は、$23.99 の購入に対する 6% の税額を計算します。関数は、金額が小数点以下 2 桁まで計算されるように、スケールの値を一時的に 2 に設定します。bc では計算結果は切り捨てられ、四捨五入は行われないことを 思い出してください。そのため、正確性は多少失われます。必要な桁数よりもう 1 桁多く使用して、最後の桁で四捨五入を行う方がよいと考えられます。このトピックの後の方で示される round2 関数は、数を小数点以下 2 桁に四捨五入します。

  2. 割り算は、数のスケールを scale の値にリセットします。これを使って、以下のように、数の整数部分を取り出すために 使用することができます。
    define integer_part(x) {
            # a local to save the value of scale
            auto old_scale
            # save the old scale, and set scale to 0
            old_scale = scale; scale=0
            # divide by 1 to truncate the number
            x /= 1
            # restore the old scale
            scale=old_scale
            return (x)
    }
  3. これは、数の小数部分を戻すために定義した関数です。
    define fractional_part(x) {return (x - integer_part(x))}
  4. 次の関数によって、与えられた小数桁数にスケールを設定することができます。
    define set_scale(x, s)
         { auto os
            os = scale
            scale = s
            x /= 1
            scale = os
            return (x)  }
    数を小数点以下 2 桁に四捨五入する関数の中で、この set_scale() を使用することができます。
    define round2(num) {
            auto temp;
            if(scale(num) < 2) return (set_scale(num, 2))
            temp = (num - set_scale(num, 2)) * 1000
            if(temp > 5) num += 0.01
            return (set_scale(num,2))
    }
    これは、金額を扱う作業の場合に非常に役に立つ関数です。例えば、sales_tax()round2() を使用して、以下のように書き直すことができます。
    define sales_tax(purchase,tax) {
        auto old_scale
        scale = 2
        tax = round2(purchase*(tax/100))
        scale = old_scale
        return (tax)
    }
  5. これは、引数の階乗を再帰的に計算する関数です。
    define fact (x) {
            if(x < 1) return 1
            return (x*fact(x-1))
    }
    以下のように、階乗関数を繰り返しによって書くこともできます。
    define fact (x) {
            auto result
            result = 1
            while(x>1) result *= x--
            return (result)
    }

    いずれの場合でも、fact(6)720 を戻します。

  6. これは別の再帰的関数です。フィボナッチ数列の n 番目のエレメントを計算します。
    define fib(n) {        if(n < 3) {                return (1)
            } else {
                    return (fib(n-1)+fib(n-2))
            }
    }

使用上の注意

  1. 字句スコープ規則を使用する C 言語と異なり、bc は動的スコープ規則を使用します。これは、例を用いて説明するとよく分かります。
    a=10
    define f1() {
            auto a;
            a = 13;
            return (f2())
    }
    define f2() {
            return (a)
    }
    f1()
    13
    f2()
    10

    f1() が呼び出されると、bc は 10 ではなく、13 を出力します。これは、f1()a の古い (グローバルの) 値を 隠して、13 に設定するためです。f2()a を参照するときには、f1() によって 動的に作成された変数を見、そして 13 を出力します。f1() は、終了するときに a を前の値に復元し ます。f2() が、f1() を介してではなく、直接呼び出された場合は、a のグローバル値を 見るので 10 を出力します。対応する C コードでは、両方の場合とも 10 を出力します。

  2. 数は、プログラム内ではストリングとして格納され、使用されるたびに数に変換されます。このことは、「定数」の値が ibase 変数の設定によって 変わるため、重要です。例えば、次の命令が bc に与えられたとします。
    define ten() {
            return (10)
    }
    ten()
    10
    ibase=16
    ten()
    16

    この例では、基数が 10 に設定されているときには、ten() は 10 進値の 10 を戻します。しかし、入力基数が 16 に変更されると、関数は 10 進値の 16 を戻します。このことは、bc プログラムでの混同によるエラーの 原因になる可能性があります。

  3. –l オプションを使用してロードされた関数のライブラリーは、ルート・ディレクトリーのファイル /usr/lib/lib.b に 格納されます。これは単純テキスト・ファイルであり 必要であれば新しい関数を追加するために中を調べたり、変更したりすることができます。
  4. 非対話式の呼び出しでは、bc は無効な入力があると終了し、入力の残りの部分はスキップされます。

ファイル

bc は以下のファイルを使用します。
/usr/lib/lib.b
–l を指定してロードされた関数のライブラリーが入っているファイル

ローカライズ

bc は、以下のローカライズ環境変数を使用します。
  • LANG
  • LC_ALL
  • LC_CTYPE
  • LC_MESSAGES
  • LC_SYNTAX
  • NLSPATH

詳しくは、ローカライズを参照してください。

終了値

0
正常終了
1
以下のいずれかによる失敗。
  • ループの外側で break 文が検出された
  • 構文解析プログラムのスタック・オーバーフロー
  • 構文エラー
  • コメント内でのファイルの終わり
  • ストリング内でのファイルの終わり
  • 数値定数が長すぎる
  • ストリングが長すぎる
  • 評価スタックが空
  • スカラーを配列に渡すことはできない
  • 配列をスカラーに渡すことはできない
  • 配列の指標が正しくない
  • 組み込み変数がパラメーターまたは自動変数として使用できない
  • name が関数ではない
  • 組み込み変数に対する値が正しくない
  • シェル・コマンドの実行が失敗した
  • 0 による割り算
  • 指数演算子に対する値が正しくない
  • 負数の平方根を取ろうとした
  • メモリー不足
2
無効なコマンド行オプション

制限

構文解析プログラムのスタックの深さは、150 レベルまでに制限されます。非常に複雑なプログラムを処理しようとすると、このスタックがオーバーフローして、エラーの原因になる可能性があります。

移植性

POSIX.2, X/Open 移植性ガイド, UNIX システム.

以下は、POSIX 標準に対する拡張です。
  • –i オプション
  • && および || 演算子
  • if … else … ステートメント
  • 2 文字以上の ID、または POSIX 文字セット以外の文字を含む ID
  • print ステートメント
  • sh ステートメント
  • return ステートメントのオプショナルの括弧

2 バイト環境では、POSIX 文字セットからの数字と演算子のみが使用できること に注意してください。ID は現行のロケールからの文字を使用できます。スクリプトを移植可能にしたい場合は、POSIX からの文字だけを使用してください。