(Note: the HyperText medium that is used to reproduce this text imposes certain restrictions on which symbols can be displayed. Those special symbols that cannot be rendered within the confines of the HyperText browser will appear as two asterisks (**). The printed version of this text will display all special symbols as the correct graphics.)
Notes for conversion:
In most EBCDIC environments are fields called "packed decimal". The hints below may help in reading and "unpacking" these codes.
In IBM "packed decimal" representation, each digit occupies four bits, i.e. IBM fits two digits in one byte. This is true for all bytes, except for the rightmost byte. In the rightmost byte, a code for the sign is placed in the low order four bits (details about this code are below).
The digits 0 through 9 are encoded in their natural hex form:
0 = "0000"
1 = "0001"
2 = "0010"
3 = "0011"
4 = "0100"
5 = "0101"
6 = "0110"
7 = "0111"
8 = "1000"
9 = "1001"
When an IBM system does arithmetic on such values, the codes
1010 through 1111 are invalid as digits, but are interpreted as
sign codes with 1010, 1100, 1110 and 1111 recognized as plus,
and 1011, 1101 recognized as minus.
The codes 0000-1001 are invalid as signs.
When an IBM system converts an "ordinary" number into this packed decimal form, the sign code generated depends on bit 12 of the Program Status Word. When bit 12 of the Program Status Word is 0, the preferred EBCDIC sign code is generated: 1100 for plus, 1101 for minus. When bit 12 of the Program Status Word is 1, the preferred ASCII-8 code is generated: 1010 for plus, 1011 for minus.
When dealing with packed decimal numeric data as a M[UMPS] programmer, handling all of the bytes, except the last is straight-forward: use the "natural" interpretation for 0000-1001, dealing with four bits at a time (using $ASCII(char)\16 for the high-order four bits and $ASCII(char)#16 for the low-order four bits. In the last byte, the high-order four bits contain the last digit, and the low-order four bits contain the sign, as indicated above.
When packed decimal data is printed out as eight-bit EBCDIC characters which are then converted to eight-bit ASCII characters, one has to work "backwards". For all but the last byte, look at the ASCII character in each byte, convert it back to EBCDIC and then use $ASCII(char)\16 for the high-order four bits and $ASCII(char)#16 for the low-order four bits to figure out what the original digits were. For the last byte, you treat the high-order four bits ($ASCII(char)\16) as a digit, and the low order four bits ($ASCII(char)#16) half as a sign according to the rules given above.
Make sure the format is indeed IBM's "packed decimal" format.
There is also something called "zoned decimal" format. It has some similarities to "packed decimal", but also some differences, especially in the meaning of the last byte.
Packed Decimal data can be decoded with:
CvtPacked(x) ; Packed Decimal
FOR I=1:1:$LENGTH(x) DO
. SET V=$ASCII(x,I)
. SET Hi=V\16
. SET Lo=V#16
. SET Result=Result*10+Hi*10+Lo
IF Lo=15!(Lo=12) SET Result=Result-Lo/10
ELSE IF Lo=13 SET Result=Lo-Result/10
ELSE SET $ECODE=",U99," ; invalid sign nibble
CvtBinary(x) ; Binary
FOR I=1:1:$LENGTH(x) SET Result=Result*256+$ASCII(x,I)
Note: These examples assume that the underlying platform is "big-endian", but that's what IBM mainframes are.