はじめに
前回の記事ではCOBOLの概要や入出力の方法を記載しました。
本記事はその続きで、COBOLの演算文法や関数を記載します。
前回記事同様、目的はAtCoderの問題を解くことなので、解くのに必要ない仕様についてはほぼ触れません。
また筆者はにわかコボラーなため、この記事には嘘も書いてあるかもしれません。ご承知おきください。
演算
代入
他の言語でいうANS = A
はCOBOLにおいて、以下の2通りで書くことができます。
COMPUTE ANS = A. MOVE A TO ANS.
なおMOVE
文は代入対象が複数存在しても良いです。
MOVE A TO ANS1 ANS2 ANS3.
加算
他の言語でいうANS = A + B
は、ANSが0の場合*1以下の3通りで書くことができます。
COMPUTE ANS = A + B. ADD A B TO ANS. ADD A TO B GIVING ANS.
他の言語に触れた方は1つ目の書き方がわかりやすいのではないかと思います。
いちいちCOMPUTE
と書く必要があるのが癪ですが……
同様に他の言語でいうANS += A
は以下の通りになります。
COMPUTE ANS = ANS + A. ADD A TO ANS. ADD A TO ANS GIVING ANS.
この場合は2つ目がわかりやすいかなと思いますが後は好みです。
なお3つ目の書き方はギャグなので*2極力避けましょう。
減算
減算の書き方は加算のときと同様です。
ANS = A - B
COMPUTE ANS = A - B. SUBTRACT B FROM A GIVING ANS.
ANS -= A
COMPUTE ANS = ANS - A. SUBTRACT A FROM ANS.
乗算
ANS = A * B
COMPUTE ANS = A * B. MULTIPLY A BY B GIVING ANS.
ANS *= A
COMPUTE ANS = ANS * A. MULTIPLY A BY ANS.
除算
除算はデフォルトで切り捨てになります。
切り捨てられる桁数は受け取り項目の有効桁の1つ下です。
なお書き方はBY
とINTO
の2通りがあるのですが、BY
が直感的っぽい代わりにGIVING
が必須となります。
ANS = A / B
COMPUTE ANS = A / B. DIVIDE B INTO A GIVING ANS. DIVIDE A BY B GIVING ANS.
ANS /= A
COMPUTE ANS = ANS / A. DIVIDE A INTO ANS. DIVIDE ANS BY A GIVING ANS.
なお四捨五入するときは、四捨五入する変数名の後ろにROUNDED
をつけます。
(後者ではANS2のみ四捨五入される)
COMPUTE ANS ROUNDED = A / B. DIVIDE B INTO A GIVING ANS1 ANS2 ROUNDED ANS3.
余りも出したいときはREMAINDER
をつけます。
DIVIDE B INTO A GIVING ANS REMAINDER REM. DIVIDE A BY B GIVING ANS REMAINDER REM.
べき乗
大抵の言語と同じです。英字の算式は(多分)ありません。
ANS = A ** B
COMPUTE ANS = A ** B.
IF文
IF <条件> [THEN] <処理1> [ELSE <処理2>] END-IF.
条件
はAND
、OR
などで複数条件を連結可能です。また同値は=
であり、==
と書く必要はありません。
THEN
は書いても書かなくてもどちらでも良いです。
処理1
は必須なため、ELSE
部のみ動かしたい場合はCONTINUE
またはNEXT SENTENCE
と書く必要があります。
なおIF
文内は.
を書いてはいけません。
なぜなら昔はEND-IF
文がなく、ピリオド(.
)があればIF文終了とみなされていたからです。
COBOLはBASICより昔から存在する言語であり、当初は多重IF文が考慮されていなかったため*3こんな仕様になっています。
そのため.
を書くと、それより前に書かれていた全てのIF
文(と後述するPERFORM
文)が終了してしまいます。
こんなクソ仕様は早くどうにかしてほしいですがレガシー言語を切り捨てられない我々のほうが悪いです本当にありがとうございました。
またELSE IF
という高尚な関数はCOBOLには存在しません(!)。
一応ELSE
の直後にIF
を書くことで擬似ELSE IF
を作り上げることができるのですが、最後にネスト数に対応したEND-IF
を書く必要があります。
IF COND1 THEN DISPLAY "1" ELSE IF COND2 THEN DISPLAY "2" ELSE IF COND3 THEN DISPLAY "3" ELSE DISPLAY "4" END-IF END-IF END-IF.
ループ
COBOLでループをするときはPERFORM
文を使います。
なおIF
文同様に、PERFORM
文内は.
を書いてはいけません。
またEXIT PERFORM
と記述することで直近のPERFORM
文から抜け出すことができます。
回数指定ループ
繰り返したい回数だけPERFORM N TIMES
と記述します。
PERFORM <回数> TIMES <処理> END-PERFORM.
例:
PERFORM 10 TIMES DISPLAY "pizza" END-PERFORM.
UNTIL文
他言語でよく使われるであろうwhile
文とは逆で、条件を満たすまでループします。
PERFORM UNTIL <条件> <処理> END-PERFORM.
例:
PERFORM UNTIL I > N ADD 1 TO I END-PERFORM.
カウンタを使うループ
一番よく使うであろう、カウンタをインクリメント/デクリメントしていくタイプのループです。
PERFORM VARYING <カウンタ> FROM <初期値> BY <変動値> UNTIL <条件> <処理> END-PERFORM.
例:
PERFORM VARYING I FROM 1 BY 1 UNTIL I > N DISPLAY A(I) END-PERFORM.
SORT
SORT
文は以下の通りに書きます。
ASCENDING
を指定すると昇順で、DESCENDING
を指定すると降順でソートされます。
SORT <配列> ON (ASCENDING|DESCENDING) KEY <ソート基準データ名> [GIVING <出力対象>].
例:
01 AL. 03 AI OCCURS 100 TIMES. 05 A PIC 9(5). (中略) SORT AI ON DESCENDING KEY A.
文字列切り抜き
COBOLで文字列から文字を切り出すには、文字(開始文字位置:文字数)
と書きます。
配列と同様1-indexed
です。
MOVE "AtCoder" TO S. DISPLAY S(2:3). *> * -> "tCo"
FUNCTION
COBOLで関数を使う場合はFUNCTION <関数名>(対象)
と記載します。
TRIM
両端のスペースを削除します。
MOVE FUNCTION TRIM(" TRIM ") TO S. DISPLAY S. *> * -> "TRIM"
LENGTH
LENGTH
は文字列の長さを返します。
ただし、そのまま変数に使うと変数の長さがそのまま返されます*4。
01 S PIC X(20). *> * (中略) MOVE FUNCTION TRIM("AtCoder") TO S. DISPLAY S. *> * -> "AtCoder " DISPLAY FUNCTION LENGTH(S). *> * -> 100
対策としてSTORED-CHAR-LENGTH
を適用するか、TRIM
関数を適用したものにLENGTH
関数を適用する必要があります。
DISPLAY FUNCTION STORED-CHAR-LENGTH(S). *> * -> 00000007 DISPLAY FUNCTION LENGTH(FUNCTION TRIM(S)). *> * -> 00000007
その他
他にもAtCoderで使えそうな関数を、こちらのサイトから独断と偏見で抜粋しました。
関数 | 引数 | 意味 |
---|---|---|
ABS | number | 絶対値を返す |
ACOS | cosine | アークコサインを返す(ラジアン) |
ASIN | sine | アークサインを返す(ラジアン) |
ATAN | tangent | アークタンジェントを返す(ラジアン) |
CHAR | integer | integerに対応した文字を返す |
CONCATENATE | string-1 [, string-2 ]... | 結合した文字列を返す |
COS | angle | コサインを返す(angleはラジアン) |
E | ネイピア数を返す | |
EXP10 | number | 10 ** numberを返す |
FRACTION-PART | number | 小数部を返す |
FACTORIAL | number | 階乗を返す |
INTEGER | number | number以下の最大の整数を返す |
LENGTH | string | 文字列の長さを返す |
LOG | number | 自然対数を返す |
LOG10 | number | 常用対数を返す |
LOWER-CASE | string | stringをすべて小文字にしたものを返す |
MAX | number-1 [, number-2 ]... | 最大値を返す |
MEAN | number-1 [, number-2 ]... | 平均値を返す |
MEDIAN | number-1 [, number-2 ]... | 中央値を返す |
MIN | number-1 [, number-2 ]... | 最小値を返す |
MOD | value, modulus | value/modulusの余りを返す |
NUMVAL | string | 文字列を数値に変換して返す |
ORD | char | charに対応した文字コードを返す |
PI | 円周率を返す | |
RANGE | number-1 [, number-2 ]... | MAX - MIN を返す |
REM | number, divisor | number/divisorの余りを返す |
REVERSE | string | stringの反転を返す |
SIN | angle | サインを返す(angleはラジアン) |
SQRT | number | 正の平方根を返す |
STORED-CHAR-LENGTH | string | 末尾スペースを覗いたstringの長さを返す |
SUBSTITUTE | string, from-1, to-1 [, from-n, to-n ]... | stringを置換する |
SUBSTITUTE-CASE | string, from-1, to-1 [, from-n, to-n ]... | 大文字小文字を区別しないSUBSTITUTE |
SUM | number-1 [, number-2 ]... | 合計を返す |
TAN | タンジェントを返す(angleはラジアン) | |
TRIM | string [, LEADING | TRAILING ] | 両端(または第2引数)のスペースを削除したstringを返す |
UPPER-CASE | string | stringをすべて大文字にしたものを返す |
最後に
ここまでCOBOLの概要や入出力について触れてきました。
ここまでの知識でAtCoderの問題をある程度解けるようになっているため、次の記事ではAtCoder Beginners Selectionの問題を解いていきます。