【COBOL】DIVIDE文完全ガイド|BY/INTO構文の違い・REMAINDER実践パターン・ゼロ除算対策・COMPUTE使い分け

【COBOL】DIVIDE文で除算(割り算)を行う方法 COBOL

COBOLのDIVIDE文は除算専用の命令です。COMPUTE文の / 演算子と違ってREMAINDER(余り)を同時に取得できる唯一の手段であり、ページ数計算・偶奇判定・循環処理・曜日計算など「商と余りを両方使う」業務パターンで欠かせません。

また、DIVIDE A BY BDIVIDE 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文の構文全体像

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で割る」と読みます。英語のニュアンスで考えると理解しやすいです。

BYとINTOの違いを数値で確認
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句を指定すると元の変数を保持したまま結果を別の変数に格納できます。

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句には複数の変数を指定できます。同じ計算結果を異なる型の変数に同時に格納するときに使います。

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文を使います。

REMAINDER句の基本
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 / OK: 別々に処理
*--- 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とは同時に使えません。

ROUNDED句の動作
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句が実行されます。本番バッチではゼロ除算が起きる可能性のある箇所に必ず記述します。

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 … で意図が明確 △ 式の一部に埋め込まれる
同じ計算の DIVIDE vs COMPUTE
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 で割った余りでグループ番号が決まります。バッチの並列分割・ラウンドロビンスケジューリングに使います。

4つのバッチキューにジョブを分配
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でエラー処理を記述します。両方実施するのが最も安全です。

よくある質問

QDIVIDE文とCOMPUTE文、どちらを使えばよいですか?
A余り(REMAINDER)が必要な場合はDIVIDE文を使います。余りが不要な単純な除算はCOMPUTE文の方が簡潔です。「DIVIDE A BY B GIVING C」は意図が明確で読みやすいという利点もあります。複数の演算子を組み合わせる計算はCOMPUTE文が適しています。
QREMAINDERはCOMPUTEの演算子で代わりに計算できますか?
Aできますが煩雑です。COMPUTE WS-R = WS-A - (WS-A / WS-B) * WS-Bで余りを計算できますが、割り算結果の切り捨てタイミングに注意が必要で、DIVIDE REMAINDER句より可読性が下がります。余りを使う場面ではDIVIDEを使う方が意図が明確で安全です。
QDIVIDE文で小数点以下を含む余りを求めることはできますか?
AREMAINDER変数に小数桁(例:PIC 9(5)V99)を定義すれば小数部の余りも格納できます。ただし実務では整数除算での余りが大半です。小数を含む余りは「余り = 被除数 − 商 × 除数」で計算されますが、精度に注意が必要です。
QDIVIDE INTO形式のGIVING省略とGIVING付きの使い分けは?
AGIVING省略(DIVIDE A INTO B)はBの値が直接書き換わります。元の値Bがその後不要な場合に使えますが、誤って元の値を失うリスクがあります。業務コードでは基本的にGIVING句を明示して元の変数を保持し、結果を別変数に格納する方が安全です。
QDIVIDE文でINTO形式を使うべき場面はありますか?
AGIVING省略のINTO形式は「変数を指定した値で直接割って更新する」場面で簡潔です。例: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の丸め処理完全ガイドも合わせてご参照ください。