Case Study 1: GlobalBank BAL-CALC — The Missing Penny
Background
Every month, GlobalBank's Operations team runs the BAL-CALC batch job to calculate and post interest for 2.3 million accounts. The job has run successfully for over fifteen years — until June 2026, when a new reconciliation report reveals a $1,247.33 monthly discrepancy between the total interest posted and the total interest calculated by the independent verification system.
"It's been there for years," Maria Chen suspects. "We just never had a report granular enough to catch it."
Derek Washington is assigned to investigate. As a junior developer, this is his first production debugging assignment.
The Investigation
Derek begins by examining the BAL-CALC source code. The core calculation loop processes each account:
*--- The original code (simplified) ---
PERFORM VARYING WS-ACCT-IDX FROM 1 BY 1
UNTIL WS-ACCT-IDX > WS-ACCT-COUNT
READ ACCT-MASTER-FILE INTO ACCT-MASTER-RECORD
COMPUTE WS-MONTHLY-INT ROUNDED =
ACCT-BALANCE * ACCT-RATE / 12
ADD WS-MONTHLY-INT TO ACCT-BALANCE
ADD WS-MONTHLY-INT TO WS-TOTAL-INT-POSTED
REWRITE ACCT-MASTER-RECORD
END-PERFORM
Derek notices several potential issues:
- The division by 12: Interest should be calculated daily and accumulated, not as a simple monthly divide
- The ROUNDED clause: Each account's interest is rounded individually
- No rounding adjustment tracking: The program does not track how much was gained or lost to rounding
The Root Cause
Derek writes a test program with 100 sample accounts. He discovers that the rounding on each account introduces a maximum error of $0.005 (half a penny). Across 2.3 million accounts:
- Maximum possible rounding error = 2,300,000 * $0.005 = $11,500 per month
- Actual observed error = $1,247.33 (consistent with statistical expectations)
The rounding errors are not systematic — they are roughly equally distributed between rounding up and rounding down. But "roughly" is not "exactly." Over 2.3 million accounts, the slight bias of COBOL's "round half up" rule creates a net positive bias — the bank is slightly overpaying interest.
The Fix
Derek proposes a three-part solution, which Maria reviews and approves:
Part 1: Switch to daily interest calculation with six-decimal intermediate precision (the "six-decimal rule")
Part 2: Implement a rounding adjustment register that tracks the cumulative rounding difference
Part 3: After processing all accounts, post the net rounding adjustment to the bank's interest suspense account — a standard accounting practice for maintaining exact reconciliation
*--- The fixed code (simplified) ---
MOVE ZERO TO WS-TOTAL-ROUND-ADJ
PERFORM VARYING WS-ACCT-IDX FROM 1 BY 1
UNTIL WS-ACCT-IDX > WS-ACCT-COUNT
READ ACCT-MASTER-FILE INTO ACCT-MASTER-RECORD
PERFORM CALC-DAILY-INTEREST-30-DAYS
COMPUTE WS-POSTED-INT ROUNDED =
WS-MONTH-ACCUM
COMPUTE WS-ROUND-DIFF =
WS-MONTH-ACCUM - WS-POSTED-INT
ADD WS-ROUND-DIFF TO WS-TOTAL-ROUND-ADJ
ADD WS-POSTED-INT TO ACCT-BALANCE
ADD WS-POSTED-INT TO WS-TOTAL-INT-POSTED
REWRITE ACCT-MASTER-RECORD
END-PERFORM
*--- Post rounding adjustment to suspense ---
PERFORM POST-ROUNDING-ADJUSTMENT
Outcome
After the fix: - Reconciliation error: $0.00 (exact match every month) - Audit finding: Closed with no penalty (the error was immaterial but the fix was appreciated) - Derek's confidence: Significantly boosted
Discussion Questions
- Why was the rounding error biased slightly positive (bank overpaying) rather than perfectly balanced?
- How would switching from "round half up" to NEAREST-EVEN (Banker's Rounding) have reduced the bias? Would it have eliminated it entirely?
- What is an "interest suspense account" and why is it the correct destination for rounding adjustments?
- If GlobalBank had 10 million accounts instead of 2.3 million, how would the monthly rounding discrepancy change?
- Derek's fix tracks per-account rounding adjustments. Could you achieve the same reconciliation by computing a single adjustment at the end (total-calculated minus total-posted)? What are the trade-offs?