I'm writing a program that converts international account numbers into the standard IBAN structure.
I have so far managed to write a program that checks the input for validity, strings said input together without embedded spaces or zeroes, converts the alphabetic characters into numbers corresponding with their position in the alphabet and creates a string with those numbers.
Now all I have to do is calculate the Mod 97 on the number and subtract the remainder from 98. If the result is a single digit then I have to insert a leading zero.
What I have right now is this:
Note: I used a pointer to get the numbers into the string before this step, so the pointer (after subtracting 1 from it) contains the total length of the string.
WORKING STORAGE SECTION.
01 WORK-FIELDS.
05 HELP FIELDS.
10 POINTER PIC S9(04) COMP.
10 DIGITIZED-STRING PIC X(66).
10 STRING-FOR-CALCULATION PIC 9(31).
05 IBAN.
10 COUNTRY-CODE PIC X(02).
10 CHECK-DIGITS PIC 9(02).
10 BANK-CODE PIC X(10).
10 BRANCH-CODE PIC X(10).
10 ACCOUNT-NUMBER PIC X(28).
10 OUTPUT-IBAN PIC X(34).
PROCEDURE DIVISION.
SUBTRACT 1 FROM POINTER
STRING DIGITIZED-STRING(1:POINTER)
DELIMITED BY SIZE
INTO STRING-FOR-CALCULATION
EVALUATE TRUE
WHEN POINTER < 32
COMPUTE IBAN-CHECK-DIGITS = 98
- FUNCTION MOD(STRING-FOR-CALCULATION, 97)
END-EVALUATE
.
I have 2 problems:
"Truncation of high-order digit positions may occur due to precision of intermediate results exceeding 31 digits."
I just don't know how to make sure it works when I'm dealing with shorter and longer numbers, which I have to split up in parts.
Additional info:
I'm using this document as a guide: www.bpfi.ie/wp-content/uploads/2014/10/MOD-97-Final-May-2013.pdf
But I have no clue how to do this in COBOL.
Also, for those who have kindly read and answered my previous questions, the reason these fields aren't National is because my project manager changed his mind about it. Now all I have to do is use a MOVE FUNCTION NATIONAL-OF
to move the IBAN-OUTPUT field to the copybook.
UPDATE
I'm using a COBOL/390 COMPILER.
Below is the code I ended up using:
WORKING-STORAGE SECTION.
01 DIGITIZED-STRING PIC X(66).
01 POINTER PIC S9(04) COMP.
01 TEST-FIELDS.
05 VERY-LONG-NUMBER.
10 VLN-FIRST-PART PIC 9(11).
10 VLN-SECOND-PART PIC 9(11).
10 VLN-THIRD-PART PIC 9(11).
10 VLN-FOURTH-PART PIC 9(11).
10 VLN-FIFTH-PART PIC 9(11).
10 VLN-SIXTH-PART PIC 9(11).
05 EXPANDED-DIVIDEND PIC 9(13).
05 FILLER
REDEFINES EXPANDED-DIVIDEND.
10 ED-REMAINDER PIC 99.
10 ED-PART PIC 9(11).
05 IRRELEVANT-ANSWER PIC 9(12).
PROCEDURE DIVISION.
MOVE SPACES TO TEST-FIELDS
MOVE ZEROES TO TEST-FLDS
MOVE DIGITIZED-STRING(1:POINTER)
TO VERY-LONG-NUMBER(66 - POINTER + 1:POINTER)
MOVE ZERO TO ED-REMAINDER
MOVE VLN-FIRST-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-SECOND-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-THIRD-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-FOURTH-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-FIFTH-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-SIXTH-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY 97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
COMPUTE CHECK-DIGITS = 98
- ED-REMAINDER
.
You do it like "long division".
1234 divided by 97 =
123 divided by 97, which gives x (doesn't matter for you) remainder 26
264 divided by 97, gives x, remainder 70
70 is the mod 97 of 1234.
Here's an example program:
ID DIVISION.
PROGRAM-ID. STAB22.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 VERY-LONG-NUMBER PIC 9(8).
01 FILLER
REDEFINES VERY-LONG-NUMBER.
05 VLN-FIRST-PART PIC 9(4).
05 VLN-SECOND-PART PIC 9(4).
01 EXPANDED-DIVIDEND PIC 9(6).
01 FILLER
REDEFINES EXPANDED-DIVIDEND.
05 ED-REMAINDER PIC 99.
05 ED-PART PIC 9(4).
01 IRRELEVANT-ANSWER PIC 9(5).
01 VALUE-FOR-MOD-97 PACKED-DECIMAL PIC 99 VALUE 97.
PROCEDURE DIVISION.
MOVE 1234 TO VERY-LONG-NUMBER
MOVE ZERO TO ED-REMAINDER
MOVE VLN-FIRST-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY VALUE-FOR-MOD-97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-SECOND-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY VALUE-FOR-MOD-97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
DISPLAY ED-REMAINDER
MOVE 12345678 TO VERY-LONG-NUMBER
MOVE ZERO TO ED-REMAINDER
MOVE VLN-FIRST-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY VALUE-FOR-MOD-97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
MOVE VLN-SECOND-PART TO ED-PART
DIVIDE EXPANDED-DIVIDEND BY VALUE-FOR-MOD-97
GIVING IRRELEVANT-ANSWER
REMAINDER ED-REMAINDER
DISPLAY ED-REMAINDER
GOBACK
.
That gives 70 and 03 as the results.
You extrapolate. I'd suggest you have six parts of 11 digits, making a 13-digit dividend each time. That will be more efficient than trying to use longer numbers with less code, using compiler option ARITH(EXTEND).