COBOLのDIVIDE文は除算専用の命令です。COMPUTE文の / 演算子と違ってREMAINDER(余り)を同時に取得できる唯一の手段であり、ページ数計算・偶奇判定・循環処理・曜日計算など「商と余りを両方使う」業務パターンで欠かせません。
また、DIVIDE A BY BとDIVIDE A INTO Bという2つの書き方は被除数と除数の位置が逆転するため、読み間違えやすい落とし穴があります。この記事では構文の違いを丁寧に整理したうえで、REMAINDER句の実践パターン、COMPUTE文との使い分け、ゼロ除算対策まで解説します。
- DIVIDE文の2つの書き方(BY形式とINTO形式)の違いと使い分け
- REMAINDER句で商と余りを同時に取得する方法
- ROUNDED句・ON SIZE ERROR / NOT ON SIZE ERROR の使い方
- COMPUTE文との使い分け基準(いつDIVIDEを使うべきか)
- REMAINDER句の実践パターン(ページ計算・偶奇判定・循環・曜日計算)
- よくある落とし穴(BY/INTOの向き・余りの符号・REMAINDERとROUNDED)
DIVIDE文の構文全体像
*--- BY形式: 「Aを Bで 割って Cに代入」---
DIVIDE 被除数A BY 除数B
GIVING 商C [ROUNDED]
[REMAINDER 余りD]
[ON SIZE ERROR 処理]
[NOT ON SIZE ERROR 処理]
END-DIVIDE
*--- INTO形式: 「BをAで 割って Cに代入」---
DIVIDE 除数A INTO 被除数B
GIVING 商C [ROUNDED]
[REMAINDER 余りD]
[ON SIZE ERROR 処理]
[NOT ON SIZE ERROR 処理]
END-DIVIDE
*--- INTO形式(GIVING省略): Bを直接書き換える ---
DIVIDE 除数A INTO 被除数B
[ROUNDED]
[ON SIZE ERROR 処理]
END-DIVIDE
| 種類 | 構文例 | 計算内容 | 特徴 |
|---|---|---|---|
| BY形式 | DIVIDE A BY B GIVING C | A÷B の結果をCに格納 | 数学式 A/B に近い語順で読みやすい |
| INTO形式(GIVING付き) | DIVIDE A INTO B GIVING C | B÷A の結果をCに格納 | A「に割り込む(into)」= Bをで割るという英語的発想 |
| INTO形式(GIVING省略) | DIVIDE A INTO B | B = B÷A(Bを上書き) | Bの値を直接書き換える。GIVINGなし |
BY形式とINTO形式の違い(混乱しやすいポイント)
DIVIDE文で最もよくあるミスが「BYとINTOで被除数と除数の位置が入れ替わる」点です。同じ変数を使っても書き方によって計算が逆になります。
BYとINTOは「割り算の向き」が逆
DIVIDE A BY B GIVING C → C = A ÷ B (A が分子)
DIVIDE A INTO B GIVING C → C = B ÷ A (B が分子)
「A INTO B」は「AがBに割り込む」→「BをAで割る」と読みます。英語のニュアンスで考えると理解しやすいです。
WORKING-STORAGE SECTION.
01 WS-A PIC 9(3) VALUE 10.
01 WS-B PIC 9(3) VALUE 50.
01 WS-RESULT PIC 9(5)V99.
PROCEDURE DIVISION.
*--- BY形式: A ÷ B ---
DIVIDE WS-A BY WS-B GIVING WS-RESULT
DISPLAY 'BY形式 (A ÷ B): ' WS-RESULT *> 10 ÷ 50 = 0.20
*--- INTO形式(GIVING付き): B ÷ A ---
DIVIDE WS-A INTO WS-B GIVING WS-RESULT
DISPLAY 'INTO形式 (B ÷ A): ' WS-RESULT *> 50 ÷ 10 = 5.00
*--- INTO形式(GIVING省略): Bの値を直接書き換え ---
*> WS-B = WS-B ÷ WS-A = 50 ÷ 10 = 5
DIVIDE WS-A INTO WS-B
DISPLAY 'INTO省略 (WS-B): ' WS-B *> 5(上書きされる)
STOP RUN.
覚え方: DIVIDE 分子 BY 分母 GIVING 結果 と読めば迷いません。BY形式は数学の分数と同じ順序なので直感的です。INTO形式を使う場合は「除数が先・被除数が後」と意識して書きましょう。
GIVING句(結果の格納先)
GIVING句を省略すると、INTO形式の被除数(最初の変数)が結果で上書きされます。GIVING句を指定すると元の変数を保持したまま結果を別の変数に格納できます。
WORKING-STORAGE SECTION.
01 WS-TOTAL PIC 9(7)V99 VALUE 15000.00.
01 WS-COUNT PIC 9(3) VALUE 4.
01 WS-AVERAGE PIC 9(7)V99.
PROCEDURE DIVISION.
*--- GIVING付き: WS-TOTALを保持したままWS-AVERAGEに格納 ---
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVERAGE
DISPLAY '合計: ' WS-TOTAL *> 15000.00(変化なし)
DISPLAY '平均: ' WS-AVERAGE *> 3750.00
*--- GIVING省略(INTO形式): WS-TOTALが上書きされる ---
*> WS-TOTAL = WS-TOTAL ÷ WS-COUNT
DIVIDE WS-COUNT INTO WS-TOTAL
DISPLAY '上書き後: ' WS-TOTAL *> 3750.00(WS-TOTALが変わる)
STOP RUN.
複数変数への同時代入
GIVING句には複数の変数を指定できます。同じ計算結果を異なる型の変数に同時に格納するときに使います。
WORKING-STORAGE SECTION.
01 WS-TOTAL-AMT PIC 9(9)V99 COMP-3 VALUE 75000.00.
01 WS-MEMBER-CNT PIC 9(3) VALUE 7.
*> 用途別に異なるPIC句で保持する変数
01 WS-AVG-EXACT PIC 9(7)V99. *> 小数2桁(正確値)
01 WS-AVG-INT PIC 9(7). *> 整数(切り捨て)
01 WS-AVG-DISP PIC ZZZ,ZZ9.99. *> 編集済み(表示用)
PROCEDURE DIVISION.
*> 同じ割り算の結果を3つの変数に同時に代入
DIVIDE WS-TOTAL-AMT BY WS-MEMBER-CNT
GIVING WS-AVG-EXACT
WS-AVG-INT
WS-AVG-DISP ROUNDED
DISPLAY '正確値: ' WS-AVG-EXACT *> 10714.28
DISPLAY '整数: ' WS-AVG-INT *> 10714
DISPLAY '表示用: ' WS-AVG-DISP *> 10,714.29(ROUNDED)
STOP RUN.
REMAINDER句(余りの取得)
DIVIDE文のみが持つ機能がREMAINDER句です。除算の商と余りを同時に求められます。COMPUTE文の/演算子では余りを取得できないため、余りが必要な場合は必ずDIVIDE文を使います。
WORKING-STORAGE SECTION.
01 WS-DIVIDEND PIC 9(5) VALUE 17. *> 被除数
01 WS-DIVISOR PIC 9(3) VALUE 5. *> 除数
01 WS-QUOTIENT PIC 9(5). *> 商
01 WS-REMAINDER PIC 9(3). *> 余り
PROCEDURE DIVISION.
DIVIDE WS-DIVIDEND BY WS-DIVISOR
GIVING WS-QUOTIENT
REMAINDER WS-REMAINDER
DISPLAY '被除数: ' WS-DIVIDEND *> 17
DISPLAY '除数: ' WS-DIVISOR *> 5
DISPLAY '商: ' WS-QUOTIENT *> 3 (17 ÷ 5 = 3 余り 2)
DISPLAY '余り: ' WS-REMAINDER *> 2
STOP RUN.
REMAINDERの計算式
余り = 被除数 − (商 × 除数)
つまり: 17 − (3 × 5) = 17 − 15 = 2
REMAINDERの符号は被除数の符号に従います(負の被除数の場合、余りも負になります)。
REMAINDERとROUNDEDの組み合わせは禁止
REMAINDER句とROUNDED句は同時に使えない
COBOLの規格上、GIVING句にROUNDEDを指定した場合、同一のDIVIDE文でREMAINDER句を使うことはできません。「ROUNDEDした商」と「余り」の組み合わせは意味が矛盾するからです。余りが必要な場合はROUNDEDなしで商を取得し、余りを別途扱います。
*--- NG: ROUNDEDとREMAINDERの同時使用(コンパイルエラー)---
*DIVIDE WS-A BY WS-B
* GIVING WS-Q ROUNDED *> NG: ROUNDEDとREMAINDERは共存不可
* REMAINDER WS-R
*--- OK: REMAINDERが必要なときはROUNDEDなしで商を取得 ---
DIVIDE WS-A BY WS-B
GIVING WS-QUOTIENT *> ROUNDEDなし(切り捨て)
REMAINDER WS-REMAINDER
*--- 商を四捨五入した値が別途必要な場合は個別に計算 ---
COMPUTE WS-QUOTIENT-ROUNDED ROUNDED = WS-A / WS-B
ROUNDED句(端数処理)
GIVING句の変数名の直後にROUNDEDを指定すると、計算結果の端数が四捨五入されます(デフォルトは切り捨て)。ただしREMAINDERとは同時に使えません。
WORKING-STORAGE SECTION.
01 WS-TOTAL PIC 9(7)V99 COMP-3 VALUE 10000.00.
01 WS-COUNT PIC 9(3) VALUE 3.
01 WS-AVG-TRUNC PIC 9(7)V99. *> 切り捨て
01 WS-AVG-ROUND PIC 9(7)V99. *> 四捨五入
PROCEDURE DIVISION.
*--- ROUNDEDなし: 切り捨て ---
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-TRUNC
DISPLAY '切り捨て: ' WS-AVG-TRUNC *> 3333.33(0.33...が切り捨て)
*--- ROUNDED: 四捨五入 ---
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-ROUND ROUNDED
DISPLAY '四捨五入: ' WS-AVG-ROUND *> 3333.33(この例では同じ)
*--- 端数が出る例 ---
MOVE 10.00 TO WS-TOTAL
MOVE 3 TO WS-COUNT
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-TRUNC
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-ROUND ROUNDED
DISPLAY '10÷3 切り捨て: ' WS-AVG-TRUNC *> 3.33
DISPLAY '10÷3 四捨五入: ' WS-AVG-ROUND *> 3.33(3桁目が3なので同じ)
MOVE 10.00 TO WS-TOTAL
MOVE 6 TO WS-COUNT
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-TRUNC
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVG-ROUND ROUNDED
DISPLAY '10÷6 切り捨て: ' WS-AVG-TRUNC *> 1.66
DISPLAY '10÷6 四捨五入: ' WS-AVG-ROUND *> 1.67(3桁目が6→繰り上げ)
STOP RUN.
丸めモード(HALF-EVEN・DOWN・UP など)の詳細な使い分けはCOBOLの丸め処理完全ガイドを参照してください。COMPUTE文でROUNDED MODE ISを使うか、DIVIDE … GIVING … ROUNDEDを組み合わせて使う方法を選べます。
ON SIZE ERROR(ゼロ除算・桁あふれ対策)
除数がゼロの場合や計算結果が格納変数に収まらない場合、ON SIZE ERROR句が実行されます。本番バッチではゼロ除算が起きる可能性のある箇所に必ず記述します。
WORKING-STORAGE SECTION.
01 WS-NUMERATOR PIC 9(9)V99 COMP-3.
01 WS-DENOMINATOR PIC 9(5) COMP-3.
01 WS-RESULT PIC 9(9)V9(4) COMP-3.
01 WS-DIV-ERROR PIC X(1) VALUE 'N'.
88 DIV-OK VALUE 'N'.
88 DIV-NG VALUE 'Y'.
PROCEDURE DIVISION.
MOVE 1000.00 TO WS-NUMERATOR
MOVE 0 TO WS-DENOMINATOR *> ゼロ除算を意図的に発生
DIVIDE WS-NUMERATOR BY WS-DENOMINATOR
GIVING WS-RESULT
ON SIZE ERROR
MOVE 'Y' TO WS-DIV-ERROR
DISPLAY 'ゼロ除算エラー: 除数=' WS-DENOMINATOR
NOT ON SIZE ERROR
DISPLAY '計算結果: ' WS-RESULT
END-DIVIDE
IF DIV-NG
MOVE 0 TO WS-RESULT *> エラー時はゼロを代入
END-IF.
WORKING-STORAGE SECTION.
01 WS-TOTAL PIC 9(9)V99 COMP-3.
01 WS-CNT PIC 9(5) COMP-3.
01 WS-AVG PIC 9(9)V99 COMP-3.
PROCEDURE DIVISION.
*> ON SIZE ERRORに頼る前に事前チェックする方が明確
IF WS-CNT = ZERO
MOVE 0 TO WS-AVG
DISPLAY '警告: 件数がゼロのため平均は計算できません'
ELSE
DIVIDE WS-TOTAL BY WS-CNT
GIVING WS-AVG ROUNDED
ON SIZE ERROR
DISPLAY '予期しない桁あふれが発生しました'
MOVE 0 TO WS-AVG
END-DIVIDE
END-IF.
| 状況 | 発生条件 | 動作 |
|---|---|---|
| ゼロ除算 | 除数が0の場合(ゼロ割り) | ON SIZE ERROR が実行される |
| 桁あふれ | 計算結果がGIVING変数のPIC句に収まらない場合 | ON SIZE ERROR が実行される |
| 正常終了 | 上記以外 | NOT ON SIZE ERROR が実行される(省略可) |
COMPUTE文との使い分け
単純な除算ならCOMPUTE文でも書けます。DIVIDEを使うべきかの判断基準を整理します。
| 観点 | DIVIDE文 | COMPUTE文 |
|---|---|---|
| 余り(REMAINDER)が必要 | ◎ DIVIDEのみが対応 | ×(別途計算が必要) |
| 単純な除算(結果のみ) | ○ 書けるが冗長になる場合も | ◎ 1行で記述可能 |
| 複数演算の組み合わせ | × DIVIDEは除算のみ | ◎ 1式で書ける |
| ROUNDEDモードの細かい指定 | △ ROUNDEDのみ(HALF-UP固定) | ◎ MODE IS HALF-EVEN等を指定可能 |
| ゼロ除算ハンドリング | ◎ ON SIZE ERRORで明示的に処理 | ◎ 同様に対応可 |
| 可読性(除算の意図を明確に) | ◎ DIVIDE … BY … で意図が明確 | △ 式の一部に埋め込まれる |
WORKING-STORAGE SECTION.
01 WS-TOTAL PIC 9(9)V99 COMP-3.
01 WS-COUNT PIC 9(5).
01 WS-AVG PIC 9(9)V99 COMP-3.
01 WS-REMAINDER PIC 9(5).
PROCEDURE DIVISION.
*--- 余りが不要な単純除算 → COMPUTEが簡潔 ---
COMPUTE WS-AVG ROUNDED = WS-TOTAL / WS-COUNT
*--- 余りが必要 → DIVIDEを使う(COMPUTEでは不可)---
DIVIDE WS-TOTAL BY WS-COUNT
GIVING WS-AVG
REMAINDER WS-REMAINDER
*--- 複合演算がある場合 → COMPUTE一択 ---
*> 税込平均単価 = (合計 * 1.10) / 件数
COMPUTE WS-AVG ROUNDED = WS-TOTAL * 1.10 / WS-COUNT
*> DIVIDEだけでは1行で書けない(MULTIPLYと組み合わせが必要)
STOP RUN.
REMAINDER句の実践パターン
ページ数・ページ番号の計算
総件数を1ページあたりの件数で割って「何ページ必要か」を求めるパターンです。余りが1以上なら最後のページに端数があるため1ページ追加します。
WORKING-STORAGE SECTION.
01 WS-TOTAL-RECS PIC 9(7).
01 WS-PAGE-SIZE PIC 9(3).
01 WS-FULL-PAGES PIC 9(5).
01 WS-LAST-PAGE-REC PIC 9(3).
01 WS-TOTAL-PAGES PIC 9(5).
PROCEDURE DIVISION.
MOVE 1057 TO WS-TOTAL-RECS *> 総件数
MOVE 50 TO WS-PAGE-SIZE *> 1ページあたり50件
DIVIDE WS-TOTAL-RECS BY WS-PAGE-SIZE
GIVING WS-FULL-PAGES
REMAINDER WS-LAST-PAGE-REC
*> 余りがあれば最終ページが追加で必要
IF WS-LAST-PAGE-REC > 0
COMPUTE WS-TOTAL-PAGES = WS-FULL-PAGES + 1
ELSE
MOVE WS-FULL-PAGES TO WS-TOTAL-PAGES
END-IF
DISPLAY '総件数: ' WS-TOTAL-RECS *> 1057
DISPLAY '満ページ: ' WS-FULL-PAGES *> 21
DISPLAY '最終ページ件数: ' WS-LAST-PAGE-REC *> 7
DISPLAY '総ページ数: ' WS-TOTAL-PAGES *> 22
STOP RUN.
偶数・奇数の判定
数値を2で割った余りが0なら偶数、1なら奇数です。行の交互背景色・帳票の段組みなどで使います。
WORKING-STORAGE SECTION.
01 WS-LINE-NO PIC 9(7).
01 WS-QUOTIENT PIC 9(7).
01 WS-REMAINDER PIC 9(1).
01 WS-IDX PIC 9(3).
PROCEDURE DIVISION.
PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 10
DIVIDE WS-IDX BY 2
GIVING WS-QUOTIENT
REMAINDER WS-REMAINDER
IF WS-REMAINDER = 0
DISPLAY WS-IDX ': 偶数'
ELSE
DISPLAY WS-IDX ': 奇数'
END-IF
END-PERFORM
STOP RUN.
*> 結果:
*> 1: 奇数 2: 偶数 3: 奇数 4: 偶数 5: 奇数
*> 6: 偶数 7: 奇数 8: 偶数 9: 奇数 10: 偶数
循環処理(ラウンドロビン分配)
N個のグループに順番に振り分けるパターンです。インデックスをN で割った余りでグループ番号が決まります。バッチの並列分割・ラウンドロビンスケジューリングに使います。
WORKING-STORAGE SECTION.
01 WS-JOB-NO PIC 9(5).
01 WS-QUEUE-COUNT PIC 9(2) VALUE 4. *> キュー数
01 WS-DUMMY-Q PIC 9(2).
01 WS-QUEUE-NO PIC 9(2). *> 振り分け先(0〜3)
01 WS-IDX PIC 9(5).
PROCEDURE DIVISION.
PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 12
DIVIDE WS-IDX BY WS-QUEUE-COUNT
GIVING WS-DUMMY-Q
REMAINDER WS-QUEUE-NO
*> 余り = キュー番号(0, 1, 2, 3 のサイクルで繰り返し)
DISPLAY 'ジョブ' WS-IDX ' → キュー' WS-QUEUE-NO
END-PERFORM
STOP RUN.
*> ジョブ1→キュー1 ジョブ2→キュー2 ジョブ3→キュー3
*> ジョブ4→キュー0 ジョブ5→キュー1 ジョブ6→キュー2 ...
時刻・時間の分解(時・分・秒)
秒単位の経過時間を「何時間何分何秒」に変換するパターンです。60で割った商と余りを繰り返し使います。
WORKING-STORAGE SECTION.
01 WS-TOTAL-SECS PIC 9(6).
01 WS-HOURS PIC 9(3).
01 WS-MINUTES PIC 9(2).
01 WS-SECONDS PIC 9(2).
01 WS-WORK PIC 9(6).
PROCEDURE DIVISION.
MOVE 7384 TO WS-TOTAL-SECS *> 7384秒 = 2時間3分4秒
*> まず分・秒に分解(秒 ÷ 60)
DIVIDE WS-TOTAL-SECS BY 60
GIVING WS-WORK *> 商=分の合計(123分)
REMAINDER WS-SECONDS *> 余り=秒(4秒)
*> 次に時・分に分解(分 ÷ 60)
DIVIDE WS-WORK BY 60
GIVING WS-HOURS *> 商=時間(2時間)
REMAINDER WS-MINUTES *> 余り=分(3分)
DISPLAY WS-HOURS '時間'
WS-MINUTES '分'
WS-SECONDS '秒' *> 2時間3分4秒
STOP RUN.
曜日計算(ツェラーの公式の余り)
日付から曜日を求めるアルゴリズム(ツェラーの公式など)では、最終的に7で割った余りが曜日番号になります。
WORKING-STORAGE SECTION.
*> ツェラーの公式: h = (q + [(13(m+1))/5] + K + [K/4] + [J/4] - 2J) mod 7
*> h: 0=土, 1=日, 2=月, 3=火, 4=水, 5=木, 6=金
01 WS-YEAR PIC 9(4).
01 WS-MONTH PIC 9(2).
01 WS-DAY PIC 9(2).
01 WS-Y PIC 9(4). *> 計算用年(1月2月は前年として扱う)
01 WS-M PIC 9(2). *> 計算用月
01 WS-K PIC 9(4). *> 年の下2桁
01 WS-J PIC 9(4). *> 年の上2桁(世紀)
01 WS-H PIC 9(5). *> 公式の計算値
01 WS-H-MOD PIC 9(2). *> 7で割った余り(曜日番号)
01 WS-DUMMY PIC 9(5).
01 WS-WDAY-NAME PIC X(6).
PROCEDURE DIVISION.
MOVE 2026 TO WS-YEAR
MOVE 1 TO WS-MONTH
MOVE 1 TO WS-DAY *> 2026年1月1日の曜日を求める
*> 1月・2月は前年の13月・14月として扱う
IF WS-MONTH <= 2
COMPUTE WS-Y = WS-YEAR - 1
COMPUTE WS-M = WS-MONTH + 12
ELSE
MOVE WS-YEAR TO WS-Y
MOVE WS-MONTH TO WS-M
END-IF
DIVIDE WS-Y BY 100 GIVING WS-J REMAINDER WS-K
*> ツェラーの公式の計算
COMPUTE WS-H = WS-DAY
+ (13 * (WS-M + 1)) / 5
+ WS-K + WS-K / 4
+ WS-J / 4
- 2 * WS-J
*> 7で割った余りで曜日を得る(負の場合に対応して7を加算)
DIVIDE WS-H BY 7 GIVING WS-DUMMY REMAINDER WS-H-MOD
IF WS-H-MOD < 0
ADD 7 TO WS-H-MOD
END-IF
EVALUATE WS-H-MOD
WHEN 0 MOVE '土曜日' TO WS-WDAY-NAME
WHEN 1 MOVE '日曜日' TO WS-WDAY-NAME
WHEN 2 MOVE '月曜日' TO WS-WDAY-NAME
WHEN 3 MOVE '火曜日' TO WS-WDAY-NAME
WHEN 4 MOVE '水曜日' TO WS-WDAY-NAME
WHEN 5 MOVE '木曜日' TO WS-WDAY-NAME
WHEN 6 MOVE '金曜日' TO WS-WDAY-NAME
END-EVALUATE
DISPLAY '2026/01/01 は ' WS-WDAY-NAME *> 木曜日
STOP RUN.
均等分割と端数処理
総量をN人(またはN部署)に均等分割するとき、余りを最初のN人に1ずつ配分するパターンです。ボーナスの分配・リソース割り当てなどで使います。
WORKING-STORAGE SECTION.
01 WS-BUDGET PIC 9(9).
01 WS-DEPT-COUNT PIC 9(2).
01 WS-BASE-ALLOC PIC 9(7). *> 基本配分額(全部署共通)
01 WS-EXTRA PIC 9(2). *> 余り(先着順に1ずつ配分)
01 WS-DEPT-ALLOC PIC 9(7). *> 各部署の最終配分額
01 WS-IDX PIC 9(2).
01 WS-TOTAL-CHECK PIC 9(9) VALUE 0.
PROCEDURE DIVISION.
MOVE 1000007 TO WS-BUDGET
MOVE 4 TO WS-DEPT-COUNT
*> 基本配分額と余りを計算
DIVIDE WS-BUDGET BY WS-DEPT-COUNT
GIVING WS-BASE-ALLOC
REMAINDER WS-EXTRA
DISPLAY '総予算: ' WS-BUDGET
DISPLAY '基本配分: ' WS-BASE-ALLOC ' × ' WS-DEPT-COUNT '部署'
DISPLAY '端数: ' WS-EXTRA ' → 先着' WS-EXTRA '部署に+1'
*> 各部署に配分
PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > WS-DEPT-COUNT
*> 先着WS-EXTRA部署には1円多く配分
IF WS-IDX <= WS-EXTRA
COMPUTE WS-DEPT-ALLOC = WS-BASE-ALLOC + 1
ELSE
MOVE WS-BASE-ALLOC TO WS-DEPT-ALLOC
END-IF
DISPLAY '部署' WS-IDX ': ' WS-DEPT-ALLOC '円'
ADD WS-DEPT-ALLOC TO WS-TOTAL-CHECK
END-PERFORM
DISPLAY '合計確認: ' WS-TOTAL-CHECK *> 1000007(元の予算と一致)
STOP RUN.
よくある落とし穴と対策
① BYとINTOの向きを間違える
症状: DIVIDE 月収 BY 12 GIVING 日額とDIVIDE 月収 INTO 12 GIVING 日額は計算が逆になります。どちらを書いても構文エラーにならないため、実行して初めて誤りに気づくことが多いです。
対策: BY形式を統一して使うことを推奨します。DIVIDE 被除数 BY 除数 GIVING 商と読める BY形式は数学の分数(被除数/除数)と語順が一致するため、INTO形式より直感的です。コードレビューで特に注意が必要なポイントです。
② REMAINDER句とROUNDED句を同時に指定する
症状: 同一のDIVIDE文でGIVING 変数 ROUNDEDとREMAINDER 変数を両方書くとコンパイルエラーになります。「四捨五入した商」と「余り」を同時に求める構文は規格上存在しません。
対策: 余りが必要な場合はROUNDEDなしのDIVIDEで商・余りを取得し、四捨五入した商が別途必要ならCOMPUTE WS-Q ROUNDED = A / Bで個別に計算します。
③ REMAINDERの符号が被除数に従うことを忘れる
症状: 負の被除数に対してDIVIDEすると余りが負の値になります。例えばDIVIDE -7 BY 3 GIVING Q REMAINDER Rの場合、Q = -2、R = -1(-7 = (-2)*3 + (-1))となります。余りの値で判定する処理で「負になる可能性」を考慮していないとバグが発生します。
対策: 被除数が負になる可能性がある場合は、DIVIDE後にIF WS-REMAINDER < 0 ADD 除数 TO WS-REMAINDERなどで正の余りに変換します。
WORKING-STORAGE SECTION.
01 WS-VALUE PIC S9(5).
01 WS-DIVISOR PIC 9(2) VALUE 7.
01 WS-QUOTIENT PIC S9(5).
01 WS-REMAINDER PIC S9(2).
PROCEDURE DIVISION.
MOVE -10 TO WS-VALUE
DIVIDE WS-VALUE BY WS-DIVISOR
GIVING WS-QUOTIENT
REMAINDER WS-REMAINDER
DISPLAY '余り(そのまま): ' WS-REMAINDER *> -3
*> 余りを常に正にしたい場合は補正
IF WS-REMAINDER < 0
ADD WS-DIVISOR TO WS-REMAINDER
END-IF
DISPLAY '余り(補正後): ' WS-REMAINDER *> 4 (-10 mod 7 = 4)
STOP RUN.
④ GIVING省略のINTO形式で元の値が失われる
症状: DIVIDE WS-COUNT INTO WS-TOTALと書くと、WS-TOTALの元の値(合計額など)が計算結果(平均値)で上書きされます。合計値がその後も必要な場合に気づかず使うとバグになります。
対策: 元の値を保持したい場合は必ずGIVING句で別の変数を指定します。DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-AVGとすればWS-TOTALは変化しません。
⑤ ゼロ除算をON SIZE ERRORで受け取らない
症状: ON SIZE ERRORを書いていない状態でゼロ除算が発生すると、コンパイラによってはプログラムが異常終了するか、WS-RESULTに不正な値が格納されます。バッチ本番でジョブが突然異常終了する事故の原因になります。
対策: 除数がゼロになりうる箇所ではDIVIDE前にゼロチェックするか、ON SIZE ERRORでエラー処理を記述します。両方実施するのが最も安全です。
よくある質問
COMPUTE WS-R = WS-A - (WS-A / WS-B) * WS-Bで余りを計算できますが、割り算結果の切り捨てタイミングに注意が必要で、DIVIDE REMAINDER句より可読性が下がります。余りを使う場面ではDIVIDEを使う方が意図が明確で安全です。DIVIDE A INTO B)はBの値が直接書き換わります。元の値Bがその後不要な場合に使えますが、誤って元の値を失うリスクがあります。業務コードでは基本的にGIVING句を明示して元の変数を保持し、結果を別変数に格納する方が安全です。DIVIDE 1000 INTO WS-SECONDS(秒→ミリ秒単位を秒に変換)のように、元の値を変換したいときに使います。ただし可読性のためにBY形式+GIVINGに統一するプロジェクトも多いです。まとめ
| 機能 | 構文例 | 説明 |
|---|---|---|
| BY形式 | DIVIDE A BY B GIVING C | A÷B。数学の A/B と語順一致で直感的 |
| INTO形式(GIVING付き) | DIVIDE A INTO B GIVING C | B÷A。A「に入る」=BをAで割る |
| INTO形式(GIVING省略) | DIVIDE A INTO B | B = B÷A。Bを直接上書き |
| REMAINDER句 | GIVING C REMAINDER D | 商CとともにD=余りを取得。DIVIDEのみの機能 |
| ROUNDED句 | GIVING C ROUNDED | 商Cを四捨五入。REMAINDERと同時不可 |
| ON SIZE ERROR | ON SIZE ERROR 処理 | ゼロ除算・桁あふれ時の処理。本番では必須 |
| 複数GIVING | GIVING C D E | 同じ計算結果を複数の変数に同時代入 |
DIVIDE文のもっとも重要な使い所はREMAINDER句(余りの取得)です。ページ計算・偶奇判定・循環分配・時刻変換など、余りが必要な業務ロジックはDIVIDE文なしには実現できません。BYとINTOの向きを常に意識して、ゼロ除算チェックを徹底することで安全に使いこなせます。
COMPUTE文の演算子全般についてはCOMPUTEで計算を行う完全ガイドを、丸め方式の詳細はCOBOLの丸め処理完全ガイドも合わせてご参照ください。
