user2152085
user2152085

Reputation:

Cobol, Finding a Percentage

I'm working on an assignment for my class, and I'm having an issue with getting a percentage to show the proper value for my COBOL Lab.

My issue is with PERCENT-DISCOUNT / WS-PERCENT-WITH-DISCOUNT (at least, I believe it is).

When the program is run, I get the result 50.0. The result I should be getting (assuming I did the math correctly by hand) is 55.6. I'm not too sure where I'm going wrong.

Here is the code that I currently have written for the program.

  *
   IDENTIFICATION DIVISION.
   PROGRAM-ID. LAB2.
   AUTHOR. XXXXXXX XXXXXXXXXXX.

  *
   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.

       SELECT IPT-FILE ASSIGN TO 'LAB2.DAT'
           ORGANIZATION IS LINE SEQUENTIAL.

       SELECT PRT-FILE ASSIGN TO 'LAB2_OUTPUT.DAT'
           ORGANIZATION IS LINE SEQUENTIAL.

  *
   DATA DIVISION.
   FILE SECTION.

  *
   FD IPT-FILE
       RECORD CONTAINS 80 CHARACTERS
       RECORDING MODE IS F
       DATA RECORD IS INPUT-RECORD.

   01 IPT-RECORD.
       05 IPT-INV-NUMBER       PIC 9(04).
       05 IPT-INV-QUANTITY     PIC 9(03).
       05 IPT-INV-DESCRIPTION  PIC X(13).
       05 IPT-INV-UNITPRICE    PIC 9999V99.
       05 IPT-INV-PROD-CLASS   PIC 9(01).

  *
   FD PRT-FILE
       RECORD CONTAINS 132 CHARACTERS
       RECORDING MODE IS F
       DATA RECORD IS PRT-LINE.

   01 PRT-LINE.
       05 FILLER               PIC X(04).
       05 PRT-INV-NUMBER       PIC 9(04).
       05 FILLER               PIC X(02).
       05 PRT-EXTENDED-PRICE   PIC Z,ZZZ,ZZ9.99.
       05 FILLER               PIC X(04).
       05 PRT-DISCOUNT-AMOUNT  PIC ZZZ,ZZ9.99.
       05 FILLER               PIC X(03).
       05 PRT-NET-PRICE        PIC Z,ZZZ,ZZ9.99.
       05 FILLER               PIC X(10).
       05 PRT-PRODUCT-CLASS    PIC 9.
       05 FILLER               PIC X(07).
       05 PRT-TRANS-PERCENT    PIC Z9.9.
       05 FILLER               PIC X(05).
       05 PRT-TRANS-CHARGE     PIC ZZZ,ZZ9.99.

  *
   WORKING-STORAGE SECTION.
  *
   01 EOF-SWITCH               PIC X VALUE 'N'.

  *
   01 WS-EXTENDED-COST         PIC 9(07)V99.

   01 WS-DISCOUNT-AMOUNT       PIC 9(06)V99.

   01 WS-NET-COST              PIC 9(07)V99.

   01 WS-TRANS-PERCENT         PIC ZZ9V9.

   01 WS-TRANS-COST            PIC 9(06)V99.

  *
   01 WS-TOTAL-EXTENDED-COST   PIC 9(09)V99 VALUE ZERO.

   01 WS-TOTAL-NET-COST        PIC 9(08)V99 VALUE ZERO.

   01 WS-TOTAL-TRANS-COST      PIC 9(08)V99 VALUE ZERO.

   01 WS-TOTAL-WITH-DISCOUNT   PIC 99V9 VALUE ZERO.

   01 WS-TOTAL-ITEMS           PIC 99V9 VALUE ZERO.

   01 WS-PERCENT-WITH-DISCOUNT PIC 99V9.

   01 WS-TOTAL-NO-DISCOUNT     PIC 99V9 VALUE ZERO.

  *
   01 HEADING-NAME.
       05 MY-NAME              PIC X(20) VALUE
           'XXXXX XXXXXXX, LAB 2'.

   01 HEADING-COLUMN-1.
       05 FILLER               PIC X(05) VALUE SPACES.
       05 COLUMN-1-INV-NUM     PIC X(03) VALUE 'INV'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-EXT-PRC     PIC X(08) VALUE 'EXTENDED'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-DISC-AMT    PIC X(08) VALUE 'DISCOUNT'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-NET-PRC     PIC X(09) VALUE 'NET PRICE'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-CLASS       PIC X(05) VALUE 'CLASS'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-TRANS-P     PIC X(05) VALUE 'TRANS'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-1-TRANS-C     PIC X(14) VALUE 'TRANSPORTATION'.

   01 HEADING-COLUMN-2.
       05 FILLER               PIC X(05) VALUE SPACES.
       05 COLUMN-2-INV-NUM     PIC X(03) VALUE 'NUM'.
       05 FILLER               PIC X(09) VALUE SPACES.
       05 COLUMN-2-EXT-PRC     PIC X(08) VALUE 'PRICE'.
       05 FILLER               PIC X(05) VALUE SPACES.
       05 COLUMN-2-DISC-AMT    PIC X(08) VALUE 'AMOUNT'.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-2-NET-PRC     PIC X(09) VALUE SPACES.
       05 FILLER               PIC X(06) VALUE SPACES.
       05 COLUMN-2-CLASS       PIC X(05) VALUE SPACES.
       05 FILLER               PIC X(08) VALUE SPACES.
       05 COLUMN-2-TRANS-P     PIC X(05) VALUE '%'.
       05 FILLER               PIC X(05) VALUE SPACES.
       05 COLUMN-2-TRANS-C     PIC X(14) VALUE 'CHARGE'.

   01 BLANK-LINE.
       05  BLANK-SPACE         PIC X VALUE SPACES.

   01 TOTAL-FOOTER.
       05 FILLER               PIC X(07) VALUE SPACES.
       05 TOTAL-EXTENDED-COST  PIC $$$$,$$$,$$9.99.
       05 FILLER               PIC X(15) VALUE SPACES.
       05 TOTAL-NET-COST       PIC $$$,$$$,$$9.99.
       05 FILLER               PIC X(23) VALUE SPACES.
       05 TOTAL-TRANS-COST     PIC $$$,$$$,$$9.99.

   01 TOTAL-NO-DISCOUNT-FOOTER.
       05 TOTAL-SENTENCE       PIC X(31) VALUE
           'TOTAL ITEMS WITHOUT DISCOUNT = '.
       05 TOTAL-NO-DISCOUNT    PIC Z9.

   01 PERCENT-DISCOUNT-FOOTER.
       05 PERCENT-SENTENCE     PIC X(44) VALUE
           'PERCENT OF ITEMS THAT RECEIVED A DISCOUNT = '.
       05 PERCENT-DISCOUNT     PIC Z9.9.

  *
   PROCEDURE DIVISION.
  *
       OPEN INPUT IPT-FILE.
       OPEN OUTPUT PRT-FILE.

  *
       WRITE PRT-LINE FROM HEADING-NAME AFTER ADVANCING 0 LINES.
       WRITE PRT-LINE FROM HEADING-COLUMN-1 AFTER ADVANCING 3 LINES.
       WRITE PRT-LINE FROM HEADING-COLUMN-2 AFTER ADVANCING 1 LINES.
       WRITE PRT-LINE FROM BLANK-LINE AFTER ADVANCING 1 LINES.

  *
       READ IPT-FILE AT END MOVE 'Y' TO EOF-SWITCH.

  *
       PERFORM MAIN-LOOP UNTIL EOF-SWITCH EQUALS 'Y'.

  *
       DIVIDE WS-TOTAL-WITH-DISCOUNT BY WS-TOTAL-ITEMS
           GIVING WS-PERCENT-WITH-DISCOUNT.

       MULTIPLY WS-PERCENT-WITH-DISCOUNT BY 100
           GIVING WS-PERCENT-WITH-DISCOUNT.

  *
       MOVE WS-TOTAL-EXTENDED-COST TO TOTAL-EXTENDED-COST.
       MOVE WS-TOTAL-NET-COST TO TOTAL-NET-COST.
       MOVE WS-TOTAL-TRANS-COST TO TOTAL-TRANS-COST.
       MOVE WS-TOTAL-NO-DISCOUNT TO TOTAL-NO-DISCOUNT.
       MOVE WS-PERCENT-WITH-DISCOUNT TO PERCENT-DISCOUNT.

  *
       WRITE PRT-LINE FROM TOTAL-FOOTER AFTER ADVANCING 3 LINES.
       WRITE PRT-LINE FROM TOTAL-NO-DISCOUNT-FOOTER AFTER
           ADVANCING 3 LINES.
       WRITE PRT-LINE FROM BLANK-LINE AFTER ADVANCING 1 LINES.
       WRITE PRT-LINE FROM PERCENT-DISCOUNT-FOOTER AFTER ADVANCING
           1 LINES.

  *
       CLOSE IPT-FILE, PRT-FILE.
       STOP RUN.

  *
   MAIN-LOOP.

       MOVE SPACES TO PRT-LINE.

  *
       MULTIPLY IPT-INV-QUANTITY BY IPT-INV-UNITPRICE
           GIVING WS-EXTENDED-COST ROUNDED.
       MOVE WS-EXTENDED-COST TO PRT-EXTENDED-PRICE.

  *
       ADD 1 TO WS-TOTAL-ITEMS

  *
       IF WS-EXTENDED-COST IS GREATER THAN 200 THEN
           MULTIPLY WS-EXTENDED-COST BY 0.11 GIVING
               WS-DISCOUNT-AMOUNT ROUNDED

           ADD 1 TO WS-TOTAL-WITH-DISCOUNT
  *
       ELSE
           MOVE ZERO TO WS-DISCOUNT-AMOUNT

           ADD 1 TO WS-TOTAL-NO-DISCOUNT

       END-IF.

  *
       IF IPT-INV-PROD-CLASS IS EQUAL TO 1 THEN
           MOVE 27.0 TO WS-TRANS-PERCENT

           MULTIPLY WS-EXTENDED-COST BY 0.27 GIVING
               WS-TRANS-COST ROUNDED
  *
       ELSE IF IPT-INV-PROD-CLASS IS EQUAL TO 2 THEN
           MOVE 17.0 TO WS-TRANS-PERCENT

           MULTIPLY WS-EXTENDED-COST BY 0.17 GIVING
               WS-TRANS-COST ROUNDED
  *
       ELSE IF IPT-INV-QUANTITY IS GREATER THAN 100 THEN
           MOVE 13.5 TO WS-TRANS-PERCENT

           MULTIPLY WS-EXTENDED-COST BY 0.135 GIVING
               WS-TRANS-COST ROUNDED
  *
       ELSE
           MOVE ZERO TO WS-TRANS-PERCENT
           MOVE 25.00 TO WS-TRANS-COST

       END-IF.

  *
       SUBTRACT WS-EXTENDED-COST FROM WS-DISCOUNT-AMOUNT
           GIVING WS-NET-COST.

       ADD WS-EXTENDED-COST TO WS-TOTAL-EXTENDED-COST.
       ADD WS-NET-COST TO WS-TOTAL-NET-COST.
       ADD WS-TRANS-COST TO WS-TOTAL-TRANS-COST.


  *
       MOVE IPT-INV-NUMBER TO PRT-INV-NUMBER.
       MOVE WS-EXTENDED-COST TO PRT-EXTENDED-PRICE.
       MOVE WS-DISCOUNT-AMOUNT TO PRT-DISCOUNT-AMOUNT.
       MOVE WS-NET-COST TO PRT-NET-PRICE.
       MOVE IPT-INV-PROD-CLASS TO PRT-PRODUCT-CLASS.
       MOVE WS-TRANS-PERCENT TO PRT-TRANS-PERCENT.
       MOVE WS-TRANS-COST TO PRT-TRANS-CHARGE.

  *
       WRITE PRT-LINE AFTER ADVANCING 1 LINES.

  *
       READ IPT-FILE AT END MOVE 'Y' TO EOF-SWITCH.

Here is the information that the .dat file holds.

2047105TYPEWRITER   0800002
1742010HANDLE       0010001
2149150USB DRIVE    1200003
3761005TAPE         5000004
2791010BOLTS        0000751
3000100STAPLER      0002007
3001101OVERHEAD PROJ0099997
3002099PENCILS      0000097
4001184CANADIAN RUGS0150294
4003050CARPET       0040000
4005001WASTE BASKETS0003793
5001010HINGES       0010001
5003010PENS (GOLD)  0049992
5004400PENS (BLACK) 0002004
8888999HIGH CHAIR   9999991
8889412PLAY PEN     0074992
0001001LOW TEST     0000019
9999999LAST RECORD  0000011

Upvotes: 0

Views: 2821

Answers (1)

Bill Woodger
Bill Woodger

Reputation: 13076

Your problem is here:

01 WS-PERCENT-WITH-DISCOUNT PIC 99V9.

When you do your divide, you store the result in that field. If you expect it to be 0.556, what you are storing is 0.5, because you have only defined one decimal place, so the two low-order decimal places are simply truncated.

When you then multiply by 100, you make that 50.0.

If you define that field with three decimal places, your expected answer should appear (I've not checked your data).

However, a better way to do it is to define more integer digits, so that the field is large enough to hold your intermediate result and multiply by 100 first. Then you can divide (and you may want to consider ROUNDED on that, but it depends on the spec for the program).

There are a few questions here on problems with COMPUTE. Reading those questions and understanding the answers will help you get a good grasp on this. In COBOL, you define the accuracy you require, and you do that by supplying the correct number of integer and decimal digits.

You could also look through some of the other COBOL questions, where you'll find lots of advice on using FILE STATUS on your files, and checking the result of each IO. You can also use the file-status field you define to check for end-of-file, rather than using AT END/NOT AT END: you should find that it needs less code, and is more easy to understand.

Ditch as many full-stops/periods as you can. You need one at the end of the PROCEDURE DIVISION header, one at the end of a procedure-name, one at the end of a procedure, and one at the end of the program (if you have no procedure-names). All the others are superfluous. Commas in code tend to distract, you may find it clearer to use indentation and formatting of the statements.

Whilst it is well-constructed, your nested-IF would be better as an EVALUATE.

You have many constants in your program. It is better to define those as data-items, with a well-chosen name, so that the code "reads", and no-one has to wonder about the significance of 0.27. You also have examples where you have two constants which are obviously related, 27.0 and 0.27 for instance, which are better served by just being one thing. If someone "maintains" the program, they may only change one of the values without changing the other (not expecting there to be another).

Look also at the use of 88-level condition names. The "switch = y" can become "end-of-invoice-file" for instance, and that 88 can be on the file-status for that file, with a value of "10".

You should test your program with an empty input file, and see if you like the results.

As a beginner with COBOL, it is not a bad shot at all.

Upvotes: 5

Related Questions