COBOL edited pictures: money with Z, comma, period, CR and minus
Numeric-edited PICTURE strings format amounts for people. Eight edited items receive the same five values; a table shows every result and the rules that produce it.
A COBOL amount field stores digits and nothing else: no decimal point, no thousands separator, no visible sign. When the number has to appear on a statement, a report line or a screen, it is moved into a numeric-edited item whose PICTURE string says where to put the separators, how to show the sign, and what to do with leading zeros. This tutorial moves five values, from a large positive amount to a small negative one, through eight edited pictures and shows the exact result of each. The program was first desk-checked against the GnuCOBOL 3.2 Programmer's Guide, with every result in the table worked out from the documented editing rules; on 29 October 2026 we compiled and ran it with GnuCOBOL 3.2, and the table now shows what it printed, which differs from the hand derivation in one cell. It follows on from the PICTURE clause lesson, and the bank statement batch job uses these pictures in its statement lines.
The program
>>SOURCE FORMAT IS FREE
*> cobol-edited-pictures-money.cob — the same five amounts through
*> eight edited PICTURE strings
*> Dialect: GnuCOBOL 3.x, free format
*> Status : desk-checked against the GnuCOBOL 3.2 Programmer's Guide;
*> compiled and run with GnuCOBOL 3.2 on 2026-10-29
*> Inputs : none (five test amounts are VALUE clauses)
*> Outputs: DISPLAY lines on the console, one per edited item per amount
*> Build : cobc -x cobol-edited-pictures-money.cob
*> Run : ./cobol-edited-pictures-money
*> (Windows: cobol-edited-pictures-money.exe)
IDENTIFICATION DIVISION.
PROGRAM-ID. EDITED-MONEY.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> The sending field is signed with two decimals. Every edited item
*> below receives the same value and shows it differently.
01 Test-Values.
05 FILLER PIC S9(7)V99 VALUE 1234567.89.
05 FILLER PIC S9(7)V99 VALUE 42.50.
05 FILLER PIC S9(7)V99 VALUE 0.
05 FILLER PIC S9(7)V99 VALUE -1234.56.
05 FILLER PIC S9(7)V99 VALUE -0.05.
01 Test-Table REDEFINES Test-Values.
05 Test-Amount OCCURS 5 TIMES PIC S9(7)V99.
77 Amount PIC S9(7)V99.
77 Show-Raw PIC -9(7).99.
*> Zero suppression and a thousands separator: 9 characters.
77 Ed-Z PIC ZZ,ZZ9.99.
*> Floating currency sign: 9 characters, four integer digits at most.
77 Ed-Dollar PIC $$,$$9.99.
*> Floating minus sign: 12 characters, six integer digits at most.
77 Ed-Minus PIC -,---,--9.99.
*> Trailing minus and trailing CR: the sign sits after the digits.
77 Ed-Trail-Minus PIC 9(6).99-.
77 Ed-CR PIC 9(6).99CR.
*> Check protection: leading zeros become asterisks.
77 Ed-Star PIC **,**9.99.
*> Simple insertion of blanks and slashes; no sign, no decimals.
77 Ed-Phone PIC 9(3)B9(3)B9(4).
77 Ed-Date PIC 9(4)/9(2)/9(2).
77 Back-To-Number PIC S9(7)V99.
77 I PIC 9.
PROCEDURE DIVISION.
Main-Paragraph.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
MOVE Test-Amount(I) TO Amount
MOVE Amount TO Show-Raw
DISPLAY "Amount " Show-Raw
MOVE Amount TO Ed-Z
MOVE Amount TO Ed-Dollar
MOVE Amount TO Ed-Minus
MOVE Amount TO Ed-Trail-Minus
MOVE Amount TO Ed-CR
MOVE Amount TO Ed-Star
MOVE Amount TO Ed-Phone
MOVE Amount TO Ed-Date
DISPLAY " ZZ,ZZ9.99 [" Ed-Z "]"
DISPLAY " $$,$$9.99 [" Ed-Dollar "]"
DISPLAY " -,---,--9.99 [" Ed-Minus "]"
DISPLAY " 9(6).99- [" Ed-Trail-Minus "]"
DISPLAY " 9(6).99CR [" Ed-CR "]"
DISPLAY " **,**9.99 [" Ed-Star "]"
DISPLAY " 9(3)B9(3)B9(4) [" Ed-Phone "]"
DISPLAY " 9(4)/9(2)/9(2) [" Ed-Date "]"
END-PERFORM
*> Going the other way: text to number with NUMVAL, then edited again.
COMPUTE Back-To-Number = FUNCTION NUMVAL(" -1234.56 ")
MOVE Back-To-Number TO Ed-Trail-Minus
DISPLAY "NUMVAL round trip [" Ed-Trail-Minus "]"
STOP RUN.
The editing symbols
Section 6.9.33 of the Programmer's Guide sorts the symbols into families, and IBM's symbol table for Enterprise COBOL lists the same set. Each symbol occupies one character of the edited field, so an edited picture is always at least as wide as the digits it can show.
Simple insertion symbols put a fixed character in the output regardless of the value: B inserts a blank, 0 inserts a zero, and / inserts a slash. Ed-Phone and Ed-Date use these to lay out a ten-digit number as three groups and an eight-digit number as a date. The comma is also an insertion symbol, but the guide notes that separators "that aren't needed will behave as if they were 9s" in the unsuppressed part and take on the suppression character in the suppressed part; the period marks where the decimal point goes and aligns the incoming value on it.
Zero suppression is the Z symbol: every leading zero in a Z position becomes a space. The asterisk does the same job but writes an asterisk instead of a space, which is why it is called check protection; a printed cheque for *****0.05 cannot be altered by writing digits into the gap.
Sign symbols come in fixed and floating forms. A single + or - at the end of the picture, or the two-character CR or DB, is fixed insertion: the guide says a minus inserts a space for a value of zero or greater and a "-" for a negative value, while CR and DB insert two spaces or the letters. A run of minus signs, plus signs or currency symbols at the start is floating insertion: the symbols behave like digit positions until the leading zeros run out, then the rightmost suppressed position receives the sign or currency character and the rest become spaces. The guide states the consequence you must remember when sizing a field: only one of +, -, CR and DB may appear, and a floating string of n symbols can show n-1 digits, because the leftmost position is reserved for the sign or currency character itself.
Line by line
The five test values sit in a FILLER group that is redefined as a five-entry table, the same compile-time initialisation trick used in the OCCURS lesson. The loop moves each value into a signed work field, prints it through Show-Raw, whose fixed leading minus shows the sign without any suppression, and then moves it into all eight edited items. A MOVE from a numeric item to a numeric-edited item aligns on the decimal point, truncates digits that do not fit on either side, and then applies the editing; the guide's own example under the period symbol shows 1234567.89 moved to 9(5).9(2) giving 34567.89, and the same high-order truncation happens in this program whenever an edited field has fewer integer positions than seven.
The last three statements go the other way. Edited items are alphanumeric as far as arithmetic is concerned; the guide says they "may not serve either as table subscripts or as source arguments on an arithmetic statement." COBOL 2002 defines a de-editing MOVE from a numeric-edited item to a numeric item, and GnuCOBOL's MOVE documentation lists numeric-edited among the sending categories a numeric receiver accepts, but we have not run that path and mark it as something to test on your compiler. FUNCTION NUMVAL (section 8.1.63) is the path we would use for text that arrives from outside the program: it accepts leading and trailing spaces, an optional sign before or after the digits, CR or DB, and a decimal point, and returns the numeric value, which the program then edits again to prove the round trip.
Worked example
The results below are what the compiled program printed (GnuCOBOL 3.2, 29 October 2026); all but one cell agree with the rules in section 6.9.33 as we first applied them by hand. Each cell is the exact edited field, with the brackets from the DISPLAY statements removed so the widths can be counted.
| Value | ZZ,ZZ9.99 | $$,$$9.99 | -,---,--9.99 | 9(6).99- | 9(6).99CR | ,9.99 | 9(3)B9(3)B9(4) | 9(4)/9(2)/9(2) |
|---|---|---|---|---|---|---|---|---|
| 1234567.89 | 34,567.89 |
$4,567.89 |
,234,567.89 |
234567.89 |
234567.89 |
34,567.89 |
000 123 4567 |
0123/45/67 |
| 42.50 | 42.50 |
$42.50 |
42.50 |
000042.50 |
000042.50 |
****42.50 |
000 000 0042 |
0000/00/42 |
| 0 | 0.00 |
$0.00 |
0.00 |
000000.00 |
000000.00 |
*****0.00 |
000 000 0000 |
0000/00/00 |
| -1234.56 | 1,234.56 |
$1,234.56 |
-1,234.56 |
001234.56- |
001234.56CR |
*1,234.56 |
000 000 1234 |
0000/12/34 |
| -0.05 | 0.05 |
$0.05 |
-0.05 |
000000.05- |
000000.05CR |
*****0.05 |
000 000 0000 |
0000/00/00 |
Reading across the first row: ZZ,ZZ9.99 has only five integer positions, so 1234567 loses its two leading digits and shows 34,567; $$,$$9.99 has four, so it shows 4,567 with the currency sign hard against the first digit; -,---,--9.99 has six, so 234,567 appears after the sign position, which is a space because the value is positive. GnuCOBOL 3.2 keeps the comma between that position and the first digit and prints ,234,567.89; our hand derivation had blanked that comma too. The two insertion-only pictures have no decimal point, so they receive the integer part right-aligned and zero-filled, which is why the phone layout shows 000 123 4567.
Reading down the fourth row, which is the negative value: the pictures with no sign symbol, ZZ,ZZ9.99, $$,$$9.99, **,**9.99 and the two insertion layouts, silently show the absolute value; the trailing minus and CR pictures show the sign after the digits; and the floating minus places "-" immediately to the left of the first significant digit. A report that prints negative balances through a picture with no sign symbol is a real and recurring defect, and the table is the argument for always including one.
The console output for the first amount, so the DISPLAY layout is clear:
Amount 1234567.89
ZZ,ZZ9.99 [34,567.89]
$$,$$9.99 [$4,567.89]
-,---,--9.99 [ ,234,567.89]
9(6).99- [234567.89 ]
9(6).99CR [234567.89 ]
**,**9.99 [34,567.89]
9(3)B9(3)B9(4) [000 123 4567]
9(4)/9(2)/9(2) [0123/45/67]
The other four blocks follow the table, and the final line is NUMVAL round trip [001234.56-].
Compile and run
cobc -x cobol-edited-pictures-money.cob
./cobol-edited-pictures-money
The source begins with >>SOURCE FORMAT IS FREE in column 8, so it needs no -free option, though the option is equivalent.
Limitations
The currency symbol is whatever the program's SPECIAL-NAMES paragraph says it is; without one, $ is the dollar sign, and the guide documents DECIMAL-POINT IS COMMA for locales that swap the roles of comma and period. GnuCOBOL accepts pictures that mix several floating symbols, such as +$$$9.99, and the guide warns that its result differs from other compilers and that such strings should be avoided in portable code; none of the eight pictures here mixes them. High-order truncation is silent: nothing tells you that 1234567.89 became 34,567.89, so size edited fields from the largest value the data can hold, not the typical one. The NUMVAL call accepts a plain decimal string; the guide describes the comma as a grouping separator for NUMVAL, but we have not verified that "1,234.56" is accepted and would use NUMVAL-C, which is documented for currency strings, before relying on it. Finally, the de-editing MOVE mentioned above is standard COBOL 2002 and documented for GnuCOBOL's MOVE, but it is not exercised in this listing.
Correction, 29 October 2026: the -,---,--9.99 result for 1234567.89 was shown as 234,567.89. A real GnuCOBOL 3.2 run prints ,234,567.89, keeping the comma next to the blank sign position; the table cell, the console line and the explanation are corrected. With that cell fixed, every result shown matches a real run, so the page now says the program was compiled and run.
Index terms cobol, gnucobol, edited picture, numeric editing, report formatting