Chapter 19 Exercises: Intrinsic Functions Reference
Tier 1: Recall and Recognition (Exercises 1-8)
Exercise 1: FUNCTION Keyword Requirement
Rewrite each of the following incorrect statements to use proper COBOL intrinsic function syntax:
a) COMPUTE WS-RESULT = SQRT(WS-VALUE)
b) MOVE UPPER-CASE(WS-NAME) TO WS-UPPER
c) DISPLAY LENGTH(WS-FIELD)
d) COMPUTE WS-MAX = MAX(WS-A WS-B WS-C)
Answers:
a) COMPUTE WS-RESULT = FUNCTION SQRT(WS-VALUE)
b) MOVE FUNCTION UPPER-CASE(WS-NAME) TO WS-UPPER
c) DISPLAY FUNCTION LENGTH(WS-FIELD)
d) COMPUTE WS-MAX = FUNCTION MAX(WS-A WS-B WS-C)
The FUNCTION keyword is mandatory in COBOL before every intrinsic function name. Unlike languages like Python or Java, you cannot simply write the function name and parentheses.
Exercise 2: Function Category Matching
Classify each intrinsic function into its category: Numeric/Math (N), String (S), Date/Time (D), or Financial (F):
| Function | Category |
|---|---|
| a) SQRT | _ |
| b) UPPER-CASE | _ |
| c) CURRENT-DATE | _ |
| d) PRESENT-VALUE | _ |
| e) LENGTH | _ |
| f) INTEGER-OF-DATE | _ |
| g) ANNUITY | _ |
| h) REVERSE | _ |
| i) MOD | _ |
| j) TRIM | _ |
Answers: a) N -- numeric/math b) S -- string c) D -- date/time d) F -- financial e) S -- string (returns numeric value, but operates on strings) f) D -- date/time g) F -- financial h) S -- string i) N -- numeric/math j) S -- string
Exercise 3: Function Argument Syntax
Fill in the blanks: In COBOL intrinsic functions, arguments are separated by _ (not _). For example, FUNCTION MAX(A B C) is correct, while FUNCTION MAX(A, B, C) follows the convention of other languages but is ____ in standard COBOL.
Answers:
Arguments are separated by spaces (not commas). FUNCTION MAX(A, B, C) is not standard in COBOL -- although some compilers accept commas as separators, the standard uses spaces. Always use spaces for portability.
Exercise 4: Return Type Identification
For each function, identify whether it returns a numeric value, an alphanumeric value, or an integer:
a) FUNCTION LENGTH("HELLO") b) FUNCTION UPPER-CASE("hello") c) FUNCTION SQRT(144) d) FUNCTION CURRENT-DATE e) FUNCTION INTEGER-OF-DATE(20260210) f) FUNCTION TRIM(" HELLO ") g) FUNCTION MOD(17 5) h) FUNCTION ORD("A")
Answers: a) Integer (5) b) Alphanumeric ("HELLO") c) Numeric (12.0) d) Alphanumeric (21-character string: YYYYMMDDHHMMSSssHOOOO) e) Integer (a day number) f) Alphanumeric ("HELLO") g) Integer (2) h) Integer (ordinal position of character in collating sequence)
Exercise 5: CURRENT-DATE Structure
The FUNCTION CURRENT-DATE returns a 21-character string. Identify what each segment represents:
| Positions | Content |
|---|---|
| 1-4 | _ |
| 5-6 | _ |
| 7-8 | _ |
| 9-10 | _ |
| 11-12 | _ |
| 13-14 | _ |
| 15-16 | _ |
| 17 | _ |
| 18-19 | _ |
| 20-21 | _ |
Answers: | Positions | Content | |-----------|---------| | 1-4 | Year (YYYY) | | 5-6 | Month (MM) | | 7-8 | Day (DD) | | 9-10 | Hour (HH, 24-hour format) | | 11-12 | Minute (MM) | | 13-14 | Second (SS) | | 15-16 | Hundredths of a second (ss) | | 17 | GMT offset sign ('+' or '-' or '0') | | 18-19 | GMT offset hours | | 20-21 | GMT offset minutes |
Exercise 6: Date Function Basics
Write COBOL statements to accomplish each of the following using intrinsic functions:
a) Convert the date 2026-02-10 (as integer 20260210) to an integer day number b) Convert an integer day number back to a YYYYMMDD date c) Calculate the number of days between January 1, 2026 and December 31, 2026 d) Get the day of the week for February 10, 2026
Answers:
* a) Date to integer day number
COMPUTE WS-DAY-NUM =
FUNCTION INTEGER-OF-DATE(20260210)
* b) Integer day number back to date
COMPUTE WS-DATE =
FUNCTION DATE-OF-INTEGER(WS-DAY-NUM)
* c) Days between two dates
COMPUTE WS-DAYS-BETWEEN =
FUNCTION INTEGER-OF-DATE(20261231) -
FUNCTION INTEGER-OF-DATE(20260101)
* Result: 364 days
* d) Day of week (1=Monday through 7=Sunday)
* Calculate integer day number, then MOD 7
COMPUTE WS-DAY-OF-WEEK =
FUNCTION MOD(
FUNCTION INTEGER-OF-DATE(20260210)
7) + 1
* Note: The exact result depends on the epoch
* used by the implementation. An easier approach:
ACCEPT WS-DAY-OF-WEEK FROM DAY-OF-WEEK
Exercise 7: String Function Basics
Write COBOL statements using intrinsic functions for each of the following:
a) Convert "john smith" to "JOHN SMITH" b) Convert "JOHN SMITH" to "john smith" c) Get the length of WS-CUSTOMER-NAME d) Reverse the string "ABCDEF" to "FEDCBA" e) Remove leading and trailing spaces from " HELLO "
Answers:
* a) Convert to uppercase
MOVE FUNCTION UPPER-CASE("john smith")
TO WS-UPPER-NAME
* b) Convert to lowercase
MOVE FUNCTION LOWER-CASE("JOHN SMITH")
TO WS-LOWER-NAME
* c) Get string length
COMPUTE WS-NAME-LEN =
FUNCTION LENGTH(WS-CUSTOMER-NAME)
* d) Reverse a string
MOVE FUNCTION REVERSE("ABCDEF")
TO WS-REVERSED
* Result: "FEDCBA"
* e) Trim spaces (COBOL 2014 TRIM function)
MOVE FUNCTION TRIM(" HELLO ")
TO WS-TRIMMED
* Result: "HELLO"
Exercise 8: Numeric Function Basics
Write COBOL COMPUTE statements using intrinsic functions:
a) Calculate the square root of 625 b) Find the maximum of three loan amounts: 50000, 75000, 25000 c) Find the minimum of three interest rates: 4.5, 3.75, 5.25 d) Calculate the remainder of 1000000 divided by 7 e) Calculate the absolute value of -5432.10
Answers:
* a) Square root
COMPUTE WS-RESULT = FUNCTION SQRT(625)
* Result: 25.0
* b) Maximum value
COMPUTE WS-MAX-LOAN =
FUNCTION MAX(50000 75000 25000)
* Result: 75000
* c) Minimum value
COMPUTE WS-MIN-RATE =
FUNCTION MIN(4.5 3.75 5.25)
* Result: 3.75
* d) Remainder (modulo)
COMPUTE WS-REMAINDER =
FUNCTION MOD(1000000 7)
* Result: 6
* e) Absolute value
COMPUTE WS-ABS-VAL =
FUNCTION ABS(-5432.10)
* Result: 5432.10
Tier 2: Comprehension and Application (Exercises 9-16)
Exercise 9: Predict the Output
Determine the exact output of each DISPLAY statement:
01 WS-A PIC S9(5) VALUE -42.
01 WS-B PIC 9(5) VALUE 16.
01 WS-C PIC X(10) VALUE "Hello ".
01 WS-D PIC X(10) VALUE " World ".
PROCEDURE DIVISION.
DISPLAY FUNCTION ABS(WS-A)
DISPLAY FUNCTION SQRT(WS-B)
DISPLAY FUNCTION LENGTH(WS-C)
DISPLAY FUNCTION LENGTH(
FUNCTION TRIM(WS-D))
DISPLAY FUNCTION UPPER-CASE(WS-C)
DISPLAY FUNCTION REVERSE("ABCDE")
DISPLAY FUNCTION MAX(10 3 7 15 2)
DISPLAY FUNCTION MOD(17 5)
DISPLAY FUNCTION ORD("A")
DISPLAY FUNCTION CHAR(66)
STOP RUN.
Answer:
00042 (ABS of -42 = 42, displayed as numeric)
4.0000... (SQRT of 16 = 4, displayed as floating point)
10 (LENGTH of WS-C including trailing spaces)
5 (LENGTH of TRIM(" World ") = "World" = 5)
HELLO (UPPER-CASE of "Hello " = "HELLO ")
EDCBA (REVERSE of "ABCDE")
15 (MAX of 10, 3, 7, 15, 2)
2 (17 MOD 5 = 2, remainder)
65 (ORD of "A" in ASCII = 66; in EBCDIC = 194)
B (CHAR(66) in ASCII = "B"; EBCDIC differs)
Note: ORD and CHAR results depend on the platform's collating sequence (ASCII vs. EBCDIC). The exact display format for numeric results depends on the receiving field's PIC clause or the DISPLAY behavior.
Exercise 10: Date Arithmetic for Banking
Write a COBOL program segment that uses intrinsic functions to solve each of the following banking date calculations:
a) A certificate of deposit (CD) matures 365 days from today. Calculate the maturity date. b) A loan payment is due on the 15th of each month. Given today's date, calculate how many days until the next payment. c) Calculate the number of business days between two dates (approximate: total days minus weekends, ignoring holidays). d) Determine if the current year is a leap year.
Answer:
* a) Maturity date = today + 365 days
MOVE FUNCTION CURRENT-DATE(1:8) TO WS-TODAY
COMPUTE WS-TODAY-INT =
FUNCTION INTEGER-OF-DATE(WS-TODAY)
COMPUTE WS-MATURITY-INT =
WS-TODAY-INT + 365
COMPUTE WS-MATURITY-DATE =
FUNCTION DATE-OF-INTEGER(WS-MATURITY-INT)
DISPLAY "MATURITY DATE: " WS-MATURITY-DATE
* b) Days until next payment on the 15th
MOVE FUNCTION CURRENT-DATE(1:4) TO WS-YEAR
MOVE FUNCTION CURRENT-DATE(5:2) TO WS-MONTH
MOVE FUNCTION CURRENT-DATE(7:2) TO WS-DAY
IF WS-DAY <= 15
STRING WS-YEAR WS-MONTH "15"
DELIMITED BY SIZE INTO WS-NEXT-DUE
ELSE
IF WS-MONTH = 12
ADD 1 TO WS-YEAR
MOVE 01 TO WS-MONTH
ELSE
ADD 1 TO WS-MONTH
END-IF
STRING WS-YEAR WS-MONTH "15"
DELIMITED BY SIZE INTO WS-NEXT-DUE
END-IF
COMPUTE WS-DAYS-UNTIL =
FUNCTION INTEGER-OF-DATE(WS-NEXT-DUE) -
FUNCTION INTEGER-OF-DATE(WS-TODAY)
* c) Approximate business days (no holiday adjustment)
COMPUTE WS-TOTAL-DAYS =
FUNCTION INTEGER-OF-DATE(WS-END-DATE) -
FUNCTION INTEGER-OF-DATE(WS-START-DATE)
COMPUTE WS-WEEKS = WS-TOTAL-DAYS / 7
COMPUTE WS-BUS-DAYS =
WS-TOTAL-DAYS - (WS-WEEKS * 2)
* d) Leap year check: Feb 29 is valid in leap years
* Try INTEGER-OF-DATE for Feb 29 of current year
MOVE FUNCTION CURRENT-DATE(1:4) TO WS-YEAR
STRING WS-YEAR "0229"
DELIMITED BY SIZE INTO WS-TEST-DATE
COMPUTE WS-TEST-INT =
FUNCTION INTEGER-OF-DATE(WS-TEST-DATE)
IF WS-TEST-INT > 0
DISPLAY WS-YEAR " IS A LEAP YEAR"
ELSE
DISPLAY WS-YEAR " IS NOT A LEAP YEAR"
END-IF
Exercise 11: Financial Functions
Write COBOL statements using the ANNUITY and PRESENT-VALUE intrinsic functions:
a) Calculate the monthly payment on a $250,000 mortgage at 6.5% annual interest for 30 years (360 months). b) Calculate the present value of receiving $1,000 per month for 5 years at 4% annual interest. c) Explain what FUNCTION ANNUITY(rate, periods) returns and how to use it to calculate a loan payment.
Answer:
* a) Monthly mortgage payment
* ANNUITY returns the ratio: payment per $1 of loan
* Monthly rate = 6.5% / 12 = 0.005417
COMPUTE WS-MONTHLY-RATE = 0.065 / 12
COMPUTE WS-PAYMENT =
250000 * FUNCTION ANNUITY(
WS-MONTHLY-RATE 360)
* Result: approximately $1,580.17
* b) Present value of monthly payments
* Monthly rate = 4% / 12 = 0.003333
COMPUTE WS-PV-RATE = 0.04 / 12
COMPUTE WS-PRESENT-VALUE =
FUNCTION PRESENT-VALUE(
WS-PV-RATE
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000
1000 1000 1000 1000 1000)
* Or use: PV = PMT / ANNUITY(rate, periods)
COMPUTE WS-PRESENT-VALUE =
1000 / FUNCTION ANNUITY(WS-PV-RATE 60)
c) FUNCTION ANNUITY(rate, periods) returns the annuity factor: the periodic payment needed to amortize exactly $1 over the given number of periods at the given periodic interest rate. To calculate the actual payment on a loan, multiply the loan amount by the annuity factor:
Payment = Principal * FUNCTION ANNUITY(periodic-rate, number-of-periods)
The periodic rate must match the payment frequency (monthly rate for monthly payments, not the annual rate).
Exercise 12: Nested Function Calls
Write a single COBOL statement that uses nested intrinsic function calls to:
a) Display the length of the trimmed uppercase version of WS-INPUT b) Compute the square root of the absolute value of WS-NEGATIVE-NUM c) Convert today's date to an integer, add 30, and convert back to a date
Answer:
* a) Nested: LENGTH of TRIM of UPPER-CASE
DISPLAY FUNCTION LENGTH(
FUNCTION TRIM(
FUNCTION UPPER-CASE(WS-INPUT)))
* b) Nested: SQRT of ABS
COMPUTE WS-RESULT =
FUNCTION SQRT(
FUNCTION ABS(WS-NEGATIVE-NUM))
* c) Nested: DATE-OF-INTEGER of (INTEGER-OF-DATE + 30)
COMPUTE WS-FUTURE-DATE =
FUNCTION DATE-OF-INTEGER(
FUNCTION INTEGER-OF-DATE(
FUNCTION CURRENT-DATE(1:8))
+ 30)
Functions can be nested to any depth. Each inner function's return value becomes the argument to the outer function. This eliminates the need for intermediate working-storage variables.
Exercise 13: String Functions for Data Cleaning
A bank receives customer data from an external source. The data may have inconsistent formatting. Write a COBOL paragraph that uses intrinsic functions to clean a customer name field:
- Remove leading and trailing spaces (TRIM)
- Convert to uppercase (UPPER-CASE)
- Verify the name is not empty after trimming (LENGTH)
- Ensure the name does not exceed 30 characters (LENGTH check)
2000-CLEAN-CUSTOMER-NAME.
MOVE FUNCTION TRIM(WS-RAW-NAME)
TO WS-TRIMMED-NAME
MOVE FUNCTION UPPER-CASE(WS-TRIMMED-NAME)
TO WS-CLEAN-NAME
COMPUTE WS-NAME-LENGTH =
FUNCTION LENGTH(
FUNCTION TRIM(WS-CLEAN-NAME))
IF WS-NAME-LENGTH = 0
MOVE "INVALID: BLANK NAME" TO WS-ERROR-MSG
SET NAME-INVALID TO TRUE
ELSE
IF WS-NAME-LENGTH > 30
MOVE "INVALID: NAME TOO LONG"
TO WS-ERROR-MSG
SET NAME-INVALID TO TRUE
ELSE
SET NAME-VALID TO TRUE
END-IF
END-IF.
Exercise 14: WHEN-COMPILED Function
Explain what FUNCTION WHEN-COMPILED returns and how it differs from FUNCTION CURRENT-DATE. Write a code snippet that displays both values and explains when each is useful in a banking application.
Answer:
DISPLAY "COMPILED ON: "
FUNCTION WHEN-COMPILED
DISPLAY "RUNNING ON: "
FUNCTION CURRENT-DATE
FUNCTION WHEN-COMPILED returns the date and time when the program was compiled. This value is fixed at compile time and never changes, no matter when or how many times the program runs. Format: YYYYMMDDHHMMSSss (16 characters).
FUNCTION CURRENT-DATE returns the current date and time at the moment the function is evaluated. This value changes with every execution.
Banking use cases: - WHEN-COMPILED is useful for audit trails: "This report was generated by program LOANRPT compiled on 2026-01-15 at 14:30:22." This helps identify which version of the program produced a given output. - CURRENT-DATE is useful for timestamps: transaction dates, report dates, audit log entries, and any time-dependent logic (cutoff processing, interest accrual dates).
Exercise 15: INTEGER and INTEGER-PART Functions
Explain the difference between FUNCTION INTEGER, FUNCTION INTEGER-PART, and standard COBOL truncation. What does each produce for the following inputs?
| Input | INTEGER | INTEGER-PART | COBOL Truncation (PIC 9(3)) |
|---|---|---|---|
| 7.8 | _ | _ | _ |
| -7.8 | _ | _ | _ |
| 7.2 | _ | _ | _ |
| -7.2 | _ | _ | _ |
Answers: | Input | INTEGER (floor) | INTEGER-PART (truncate toward 0) | COBOL Truncation | |-------|---------|-------------|----------------------------| | 7.8 | 7 | 7 | 007 | | -7.8 | -8 | -7 | N/A (unsigned) | | 7.2 | 7 | 7 | 007 | | -7.2 | -8 | -7 | N/A (unsigned) |
INTEGER returns the greatest integer not greater than the argument (floor function). For positive numbers, it truncates. For negative numbers, it rounds away from zero: INTEGER(-7.2) = -8.
INTEGER-PART truncates toward zero (removes the decimal part). For both positive and negative numbers, it simply drops the fractional digits: INTEGER-PART(-7.2) = -7.
COBOL truncation (moving to an integer PIC field) truncates toward zero, similar to INTEGER-PART, but only for unsigned fields.
Exercise 16: Statistical Functions
Write COBOL statements to calculate statistical measures for a set of quarterly loan default rates stored in a table:
01 WS-RATES.
05 WS-RATE PIC 9V9(4) OCCURS 4.
* Values: 0.0234, 0.0187, 0.0312, 0.0256
Calculate: a) The mean (average) default rate b) The median default rate c) The range (max - min) d) The standard deviation (if available)
Answer:
* a) Mean
COMPUTE WS-MEAN =
FUNCTION MEAN(
WS-RATE(1) WS-RATE(2)
WS-RATE(3) WS-RATE(4))
* Result: (0.0234+0.0187+0.0312+0.0256)/4
* = 0.0247 (approx)
* b) Median
COMPUTE WS-MEDIAN =
FUNCTION MEDIAN(
WS-RATE(1) WS-RATE(2)
WS-RATE(3) WS-RATE(4))
* Sorted: 0.0187, 0.0234, 0.0256, 0.0312
* Median of 4 values = avg of middle 2
* = (0.0234 + 0.0256) / 2 = 0.0245
* c) Range
COMPUTE WS-RANGE =
FUNCTION MAX(
WS-RATE(1) WS-RATE(2)
WS-RATE(3) WS-RATE(4))
- FUNCTION MIN(
WS-RATE(1) WS-RATE(2)
WS-RATE(3) WS-RATE(4))
* Result: 0.0312 - 0.0187 = 0.0125
* d) Standard deviation (IBM Enterprise COBOL)
COMPUTE WS-STDDEV =
FUNCTION STANDARD-DEVIATION(
WS-RATE(1) WS-RATE(2)
WS-RATE(3) WS-RATE(4))
Tier 3: Apply (Exercises 17-22)
Exercise 17: Debug These Function Calls
Find and fix the errors in each statement:
a) COMPUTE WS-LEN = LENGTH(WS-NAME)
b) MOVE FUNCTION UPPER-CASE WS-NAME TO WS-UPPER
c) COMPUTE WS-DAYS = FUNCTION INTEGER-OF-DATE("20260210")
d) DISPLAY FUNCTION MAX(WS-A, WS-B, WS-C)
e) COMPUTE WS-X = FUNCTION SQRT(-25)
Answers:
a) Missing FUNCTION keyword.
Fix: COMPUTE WS-LEN = FUNCTION LENGTH(WS-NAME)
b) Missing parentheses around the argument.
Fix: MOVE FUNCTION UPPER-CASE(WS-NAME) TO WS-UPPER
c) INTEGER-OF-DATE expects a numeric argument (PIC 9(8)), not a string literal.
Fix: COMPUTE WS-DAYS = FUNCTION INTEGER-OF-DATE(20260210) (numeric literal, no quotes)
d) Arguments should be separated by spaces, not commas (though some compilers accept commas).
Fix: DISPLAY FUNCTION MAX(WS-A WS-B WS-C)
e) SQRT of a negative number is mathematically undefined and will cause a runtime error.
Fix: Take the absolute value first: COMPUTE WS-X = FUNCTION SQRT(FUNCTION ABS(-25))
Exercise 18: Account Number Validation with Functions
Write a COBOL paragraph that validates a 10-digit bank account number using intrinsic functions. The validation rules are:
- The account number must be exactly 10 characters (use LENGTH)
- After trimming, the account number must still be 10 characters (no embedded spaces)
- The first two characters must be uppercase letters (use ORD to check range)
- The remaining 8 characters must be numeric (use NUMVAL or manual checking)
- The account number check digit (last digit) must be valid (Luhn algorithm)
3000-VALIDATE-ACCOUNT.
COMPUTE WS-ACCT-LEN =
FUNCTION LENGTH(WS-ACCOUNT-NUM)
IF WS-ACCT-LEN NOT = 10
MOVE "INVALID LENGTH" TO WS-ERROR-MSG
SET ACCT-INVALID TO TRUE
GO TO 3000-EXIT
END-IF
COMPUTE WS-TRIMMED-LEN =
FUNCTION LENGTH(
FUNCTION TRIM(WS-ACCOUNT-NUM))
IF WS-TRIMMED-LEN NOT = 10
MOVE "EMBEDDED SPACES" TO WS-ERROR-MSG
SET ACCT-INVALID TO TRUE
GO TO 3000-EXIT
END-IF
* Check first 2 chars are uppercase A-Z
COMPUTE WS-ORD-1 =
FUNCTION ORD(WS-ACCOUNT-NUM(1:1))
COMPUTE WS-ORD-2 =
FUNCTION ORD(WS-ACCOUNT-NUM(2:1))
* In ASCII: A=65, Z=90
IF WS-ORD-1 < FUNCTION ORD("A")
OR WS-ORD-1 > FUNCTION ORD("Z")
OR WS-ORD-2 < FUNCTION ORD("A")
OR WS-ORD-2 > FUNCTION ORD("Z")
MOVE "PREFIX NOT ALPHA" TO WS-ERROR-MSG
SET ACCT-INVALID TO TRUE
GO TO 3000-EXIT
END-IF
* Check positions 3-10 are numeric
IF WS-ACCOUNT-NUM(3:8) IS NOT NUMERIC
MOVE "SUFFIX NOT NUMERIC" TO WS-ERROR-MSG
SET ACCT-INVALID TO TRUE
GO TO 3000-EXIT
END-IF
SET ACCT-VALID TO TRUE.
3000-EXIT.
EXIT.
Exercise 19: Date Functions for Loan Processing
Write a complete COBOL program that uses intrinsic date functions to calculate loan maturity information. The program reads a loan file and for each loan:
- Calculate the maturity date (origination date + term in months)
- Calculate days remaining until maturity from today
- Determine if the loan is past due (maturity date < today)
- Calculate the loan age in years and months
- Display all calculated values
Use FUNCTION CURRENT-DATE, FUNCTION INTEGER-OF-DATE, and FUNCTION DATE-OF-INTEGER.
Answer: See code/exercise-solutions.cob (EX19SOL)
Exercise 20: String Functions for Report Formatting
Write a COBOL paragraph that formats a bank customer's name for display on a check or statement. The input fields are separate first name, middle initial, and last name fields. Apply the following transformations using intrinsic functions:
- Trim all three name parts
- Convert to uppercase
- Build the display name as "LAST, FIRST M."
- If the total length exceeds 35 characters, truncate the first name
- Right-pad the result to exactly 40 characters
4000-FORMAT-NAME.
MOVE FUNCTION TRIM(
FUNCTION UPPER-CASE(WS-LAST-NAME))
TO WS-CLEAN-LAST
MOVE FUNCTION TRIM(
FUNCTION UPPER-CASE(WS-FIRST-NAME))
TO WS-CLEAN-FIRST
MOVE FUNCTION TRIM(
FUNCTION UPPER-CASE(WS-MIDDLE-INIT))
TO WS-CLEAN-MI
STRING WS-CLEAN-LAST DELIMITED BY SPACES
", " DELIMITED BY SIZE
WS-CLEAN-FIRST DELIMITED BY SPACES
" " DELIMITED BY SIZE
WS-CLEAN-MI DELIMITED BY SPACES
"." DELIMITED BY SIZE
INTO WS-DISPLAY-NAME
WITH POINTER WS-PTR
END-STRING
* Check total length
COMPUTE WS-NAME-LEN = WS-PTR - 1
IF WS-NAME-LEN > 35
* Truncate at 35 characters
MOVE WS-DISPLAY-NAME(1:35)
TO WS-DISPLAY-NAME
MOVE 35 TO WS-NAME-LEN
END-IF
* Pad to 40 characters (MOVE pads with spaces)
MOVE WS-DISPLAY-NAME TO WS-FORMATTED-NAME.
Exercise 21: Financial Calculations with Intrinsic Functions
Write a COBOL program that calculates a complete amortization schedule for the first 12 months of a loan. For each month, use intrinsic functions to calculate:
- Monthly payment (using ANNUITY)
- Interest portion of payment
- Principal portion of payment
- Remaining balance
- Total interest paid to date
- Total principal paid to date
Input: Loan amount = $100,000, Annual rate = 7.5%, Term = 360 months
Answer:
IDENTIFICATION DIVISION.
PROGRAM-ID. AMORTIZE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRINCIPAL PIC S9(9)V99 VALUE 100000.00.
01 WS-ANNUAL-RATE PIC 9V9(6) VALUE 0.075.
01 WS-MONTHLY-RATE PIC 9V9(8).
01 WS-TERM PIC 9(4) VALUE 360.
01 WS-PAYMENT PIC S9(7)V99.
01 WS-BALANCE PIC S9(9)V99.
01 WS-INTEREST-PMT PIC S9(7)V99.
01 WS-PRINCIPAL-PMT PIC S9(7)V99.
01 WS-TOTAL-INTEREST PIC S9(9)V99 VALUE 0.
01 WS-TOTAL-PRINCIPAL PIC S9(9)V99 VALUE 0.
01 WS-MONTH PIC 9(4).
01 WS-DISPLAY-BAL PIC $$$,$$$,$$9.99.
01 WS-DISPLAY-PMT PIC $$,$$$,$$9.99.
01 WS-DISPLAY-INT PIC $$,$$$,$$9.99.
01 WS-DISPLAY-PRI PIC $$,$$$,$$9.99.
PROCEDURE DIVISION.
0000-MAIN.
COMPUTE WS-MONTHLY-RATE =
WS-ANNUAL-RATE / 12
COMPUTE WS-PAYMENT =
WS-PRINCIPAL *
FUNCTION ANNUITY(WS-MONTHLY-RATE WS-TERM)
MOVE WS-PRINCIPAL TO WS-BALANCE
DISPLAY "MONTH PAYMENT INTEREST"
" PRINCIPAL BALANCE"
DISPLAY "----- ---------- ----------"
" ---------- --------------"
PERFORM VARYING WS-MONTH FROM 1 BY 1
UNTIL WS-MONTH > 12
COMPUTE WS-INTEREST-PMT ROUNDED =
WS-BALANCE * WS-MONTHLY-RATE
COMPUTE WS-PRINCIPAL-PMT =
WS-PAYMENT - WS-INTEREST-PMT
SUBTRACT WS-PRINCIPAL-PMT
FROM WS-BALANCE
ADD WS-INTEREST-PMT
TO WS-TOTAL-INTEREST
ADD WS-PRINCIPAL-PMT
TO WS-TOTAL-PRINCIPAL
MOVE WS-PAYMENT TO WS-DISPLAY-PMT
MOVE WS-INTEREST-PMT TO WS-DISPLAY-INT
MOVE WS-PRINCIPAL-PMT TO WS-DISPLAY-PRI
MOVE WS-BALANCE TO WS-DISPLAY-BAL
DISPLAY WS-MONTH " "
WS-DISPLAY-PMT " "
WS-DISPLAY-INT " "
WS-DISPLAY-PRI " "
WS-DISPLAY-BAL
END-PERFORM
DISPLAY " "
MOVE WS-TOTAL-INTEREST TO WS-DISPLAY-INT
MOVE WS-TOTAL-PRINCIPAL TO WS-DISPLAY-PRI
DISPLAY "12-MONTH TOTALS:"
DISPLAY " TOTAL INTEREST: " WS-DISPLAY-INT
DISPLAY " TOTAL PRINCIPAL: " WS-DISPLAY-PRI
STOP RUN.
Exercise 22: Function-Based Data Transformation
Write a COBOL program that reads a file of raw customer data and uses intrinsic functions to transform and clean each record. The transformations are:
- Customer name: TRIM + UPPER-CASE
- Phone number: extract digits only (use INSPECT and LENGTH)
- Date of birth: validate using INTEGER-OF-DATE (returns 0 for invalid dates)
- Annual income: calculate monthly income using division, apply ABS to ensure positive
- Account age: calculate from opening date to CURRENT-DATE using INTEGER-OF-DATE
For each record, write the cleaned data to an output file and display a count of records with validation errors.
Hint: Some transformations (like extracting digits from a phone number) cannot be done with a single intrinsic function and require INSPECT TALLYING or STRING/UNSTRING in combination with functions.
Tier 4: Analyze (Exercises 23-28)
Exercise 23: Function Performance Analysis
A bank processes 10 million transactions nightly. Each transaction requires calculating the number of days between two dates. Compare the performance of:
Approach A: Using intrinsic functions
COMPUTE WS-DAYS =
FUNCTION INTEGER-OF-DATE(WS-END-DATE) -
FUNCTION INTEGER-OF-DATE(WS-START-DATE)
Approach B: Using a hand-coded date difference subroutine (50 lines of code that manually accounts for month lengths and leap years)
Analyze: code complexity, correctness risk, CPU cost per call, maintainability, and portability. Which approach would you recommend?
Hint: Intrinsic functions are compiled into inline machine code or optimized library calls. They have been thoroughly tested by the compiler vendor across billions of invocations. Hand-coded date routines are custom code that must be individually tested and maintained.
Exercise 24: Cross-Platform Function Availability
A COBOL application is being migrated from IBM Enterprise COBOL (z/OS) to GnuCOBOL (Linux). Identify which of the following functions may have availability or behavior differences:
a) FUNCTION CURRENT-DATE b) FUNCTION UPPER-CASE / LOWER-CASE c) FUNCTION NUMVAL / NUMVAL-C d) FUNCTION ORD / CHAR e) FUNCTION ANNUITY / PRESENT-VALUE f) FUNCTION TRIM g) FUNCTION RANDOM
For each, describe the potential difference and how to handle it during migration.
Hint: The biggest differences are in EBCDIC vs. ASCII character handling (ORD, CHAR, UPPER-CASE) and in the availability of newer COBOL 2014 functions (TRIM, CONCATENATE).
Exercise 25: Replacing Hand-Coded Routines with Functions
The following 45-line paragraph converts a date from YYYYMMDD to a Julian day number. Rewrite it using a single FUNCTION INTEGER-OF-DATE call. Then analyze what bugs might be lurking in the hand-coded version.
5000-DATE-TO-JULIAN.
MOVE WS-DATE-YYYY TO WS-YEAR
MOVE WS-DATE-MM TO WS-MONTH
MOVE WS-DATE-DD TO WS-DAY
COMPUTE WS-A = (14 - WS-MONTH) / 12
COMPUTE WS-Y = WS-YEAR + 4800 - WS-A
COMPUTE WS-M = WS-MONTH + 12 * WS-A - 3
COMPUTE WS-JULIAN =
WS-DAY + (153 * WS-M + 2) / 5
+ 365 * WS-Y + WS-Y / 4
- WS-Y / 100 + WS-Y / 400 - 32045.
Hint: The hand-coded version may have issues with integer truncation in the division steps, edge cases around February 29, and century boundary handling. FUNCTION INTEGER-OF-DATE handles all of these correctly.
Exercise 26: Function Composition Design Patterns
Design a set of reusable COBOL sections (not functions -- COBOL does not have user-defined functions in the traditional sense) that wrap intrinsic function calls for common banking operations. Each section should accept parameters through WORKING-STORAGE and return results through WORKING-STORAGE. Implement:
a) FORMAT-CURRENCY: Accepts a numeric amount and returns a formatted string with currency symbol, commas, and two decimal places b) DAYS-BETWEEN: Accepts two YYYYMMDD dates and returns the number of days between them (handling the case where the end date is before the start date) c) ADD-MONTHS: Accepts a YYYYMMDD date and a number of months, returns the new date (handling month-end edge cases like adding 1 month to January 31)
Hint: ADD-MONTHS is the most complex because month lengths vary. If January 31 + 1 month = February 28 (or 29), you need special handling. One approach: extract year/month, add months, check if the day exceeds the new month's length, and adjust.
Exercise 27: NUMVAL and NUMVAL-C for Financial Input
A bank's ATM network sends transaction amounts as formatted strings like "$1,234.56" and "-$500.00". Write a COBOL paragraph that uses NUMVAL-C to convert these strings to numeric values for processing. Handle the following edge cases:
a) Amounts with dollar sign and commas: "$1,234.56" b) Negative amounts: "-$500.00" or "($500.00)" c) Amounts without formatting: "1234.56" d) Invalid amounts: "N/A", "PENDING", or blank
6000-PARSE-AMOUNT.
IF WS-RAW-AMOUNT = SPACES
OR WS-RAW-AMOUNT = "N/A"
OR WS-RAW-AMOUNT = "PENDING"
MOVE 0 TO WS-NUMERIC-AMOUNT
SET AMOUNT-INVALID TO TRUE
GO TO 6000-EXIT
END-IF
* NUMVAL-C converts formatted numeric strings
* Second argument is the currency sign to strip
COMPUTE WS-NUMERIC-AMOUNT =
FUNCTION NUMVAL-C(WS-RAW-AMOUNT "$")
SET AMOUNT-VALID TO TRUE.
6000-EXIT.
EXIT.
Discuss: What happens if NUMVAL-C receives truly invalid data (non-numeric characters other than currency symbols and commas)? How should you protect against this?
Hint: NUMVAL-C will cause a runtime error (or undefined behavior) on truly invalid data. You may need to validate the string before calling NUMVAL-C, or use TEST-NUMVAL-C (COBOL 2014) to check if the string is convertible.
Exercise 28: Function-Based Encryption Seed
A bank needs to generate pseudo-random customer IDs for anonymized test data. Design a scheme using FUNCTION RANDOM and other intrinsic functions:
- Seed the random number generator with a value derived from FUNCTION CURRENT-DATE
- Generate a random number between 1000000000 and 9999999999 for each customer ID
- Ensure no duplicates (or handle them)
- Discuss the limitations of FUNCTION RANDOM for this use case
Hint: FUNCTION RANDOM(seed) initializes the random sequence. Subsequent calls to FUNCTION RANDOM (without arguments) return the next pseudo-random number between 0 and 1. To get a specific range: ID = FUNCTION INTEGER(RANDOM * 9000000000) + 1000000000. However, FUNCTION RANDOM is NOT cryptographically secure and should NEVER be used for actual security-sensitive applications.
Tier 5: Create (Exercises 29-33)
Exercise 29: Complete Loan Amortization System
Write a complete COBOL program that generates a full amortization schedule for a bank loan. The program should:
- Read loan parameters from an input file (principal, rate, term, start date)
- Use FUNCTION ANNUITY to calculate the monthly payment
- Use FUNCTION INTEGER-OF-DATE / DATE-OF-INTEGER to calculate each payment date (adding 1 month to the previous date)
- For each month, calculate interest, principal, and remaining balance
- Handle the final payment adjustment (last payment may differ slightly to zero out the balance)
- Produce a formatted report with page headings, detail lines, and summary totals
- Calculate and display total interest, total principal, and effective annual rate
Include complete error handling for invalid inputs (negative amounts, zero rates, impossible dates).
Hint: Adding "1 month" to a date is not as simple as adding 30 or 31 days. You must increment the month, handle year boundaries (December to January), and adjust the day if the new month has fewer days (e.g., January 31 + 1 month = February 28).
Exercise 30: Financial Calculator Suite
Write a COBOL program that implements a complete financial calculator using intrinsic functions. The calculator should support:
- Loan payment -- given principal, rate, and term, calculate payment (ANNUITY)
- Future value -- given payment, rate, and term, calculate the future value of an annuity
- Present value -- given payment, rate, and term, calculate present value (PRESENT-VALUE)
- Interest rate solver -- given principal, payment, and term, find the rate (iterative approach since there is no direct function)
- Term solver -- given principal, payment, and rate, find the number of payments needed
- Compound interest -- given principal, rate, and time, calculate the future value with compound interest
The program reads calculation requests from an input file and writes results to a report file.
Hint: The interest rate solver (item 4) requires an iterative approach (Newton-Raphson or bisection) because there is no intrinsic function that directly solves for rate. Start with an estimated rate and converge.
Exercise 31: Date-Driven Batch Scheduler
Write a COBOL program that uses date functions to determine which batch processes should run on a given day. The scheduling rules are:
- Daily processes run every day
- Weekly processes run on Monday (use INTEGER-OF-DATE MOD 7 to find the day of week)
- Monthly processes run on the last business day of each month
- Quarterly processes run on the last business day of each quarter
- Year-end processes run on December 31 (or the last business day before it)
- If a scheduled date falls on a weekend, the process runs on the preceding Friday
The program reads a schedule definition file and today's date (from CURRENT-DATE), and produces a list of processes to execute today.
Hint: Determining the "last business day of the month" requires calculating the last day of the month, checking if it is a Saturday or Sunday, and adjusting backward. The last day of a month can be found by going to the 1st of the next month and subtracting 1 day (using INTEGER-OF-DATE and DATE-OF-INTEGER).
Exercise 32: Data Quality Dashboard
Write a COBOL program that analyzes a customer file and produces a data quality report using intrinsic functions. For each record, assess:
- Name quality: non-blank, properly capitalized (first letter uppercase, rest lowercase -- check with UPPER-CASE/LOWER-CASE comparison), no numeric characters
- Date quality: all date fields pass INTEGER-OF-DATE validation, dates are within reasonable ranges (not in the future, not before 1900)
- Numeric quality: all amount fields are non-negative (ABS check), within reasonable bounds (no balance over $999,999,999)
- Completeness: percentage of fields that are non-blank
Produce a summary dashboard showing: - Total records analyzed - Records passing all quality checks - Failure counts by category (name, date, numeric, completeness) - Data quality percentage (passing / total * 100) - Mean and standard deviation of account balances (using MEAN and STANDARD-DEVIATION)
Exercise 33: Multi-Currency Transaction Processor
Write a COBOL program for a bank's international wire transfer system that uses intrinsic functions for:
- Currency conversion with precision control (use ROUNDED and explicit rounding modes)
- Date calculations for value dates (payment date + 2 business days for international transfers)
- String functions for SWIFT message formatting (UPPER-CASE for BIC codes, LENGTH validation for IBAN numbers, TRIM for free-text fields)
- Financial calculations for correspondent banking fees (ANNUITY for fee amortization if the fee is spread over multiple transactions)
- Random reference number generation (RANDOM seeded with CURRENT-DATE)
Process a file of wire transfer requests and produce: - A processed transactions file with calculated fees and value dates - A SWIFT message file with properly formatted messages - An exception report for failed validations - A daily summary with statistical analysis (MEAN, MEDIAN, STANDARD-DEVIATION of transfer amounts by currency)