我目前正在学习一周的旧编程语言COBOL,但遇到了问题。这是Cobol计划的样本。
IDENTIFICATION DIVISION.
PROGRAM-ID. MONTHLY.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO "USERINPUT.DAT".
SELECT OUT-FILE ASSIGN TO "USEROUTPUT.DAT".
DATA DIVISION.
FILE SECTION.
FD IN-FILE
LABEL RECORDS ARE STANDARD
DATA RECORD IS IN-REC.
01 IN-REC.
02 C-NAME PIC X(25).
02 STREET PIC X(20).
02 ZIP-CODE PIC X(15).
02 CREDIT PIC 9(6)V99.
02 MONTH PIC 99.
02 FILLER PIC XX VALUE "\n".
FD OUT-FILE
LABEL RECORDS ARE STANDARD
DATA RECORD IS OUT-REC.
01 OUT-REC PIC X(80).
*-----------------------
WORKING-STORAGE SECTION.
*-----------------------
01 HDG-01.
02 FILLER PIC X(27) VALUE SPACES.
02 FILLER PIC X(27) VALUE "ABC Loans & Savings Company".
01 HDG-02.
02 FILLER PIC X(28) VALUE SPACES.
02 FILLER PIC X(25) VALUE "Ayala Avenue, Makati City".
01 HDG-03.
02 FILLER PIC X(30) VALUE SPACES.
02 FILLER PIC X(20) VALUE "SCHEDULE OF PAYMENTS".
01 HDG-04.
02 FILLER PIC X(28) VALUE SPACES.
02 FILLER PIC X(15) VALUE "ORIGINAL AMOUNT".
02 REC-CREDIT PIC Z(5)9.99.
01 HDG-05.
02 FILLER PIC X(14) VALUE SPACES.
02 FILLER PIC X(9) VALUE "MONTH".
02 FILLER PIC X(11) VALUE "INTEREST".
02 FILLER PIC X(17) VALUE "TOTAL-PAYMENT".
02 FILLER PIC X(14) VALUE "UNPAID-BALANCE".
01 TRANSFER-LINE.
02 FILLER PIC X(16) VALUE SPACES.
02 REC-MONTH PIC 99.
02 FILLER PIC X(6) VALUE SPACES.
02 INTEREST PIC 9(3)V99.
02 FILLER PIC X(7) VALUE SPACES.
02 TOTAL-PAY PIC 9(6)v99.
02 FILLER PIC X(10) VALUE SPACES.
02 UNPAID-BAL PIC 9(6)v99.
01 PRINT-LINE.
02 FILLER PIC X(16) VALUE SPACES.
02 FILLER PIC 99.
02 FILLER PIC X(6) VALUE SPACES.
02 FILLER PIC ZZ9.99.
02 FILLER PIC X(7) VALUE SPACES.
02 FILLER PIC Z(5)9.99.
02 FILLER PIC X(10) VALUE SPACES.
02 FILLER PIC Z(5)9.99.
01 PRINT-NULL.
02 FILLER PIC X(16) VALUE SPACES.
02 FILLER PIC XX VALUE "--".
02 FILLER PIC X(6) VALUE SPACES.
02 FILLER PIC XXXXX VALUE "-----".
02 FILLER PIC X(7) VALUE SPACES.
02 FILLER PIC X(9) VALUE "---------".
02 FILLER PIC X(9) VALUE SPACES.
02 FILLER PIC X(9) VALUE "---------".
01 X PIC 99.
01 REM PIC 999.
01 CHECK-MONTH PIC 99.
01 CLIENT-NO PIC 9.
01 PRINT-ASTERISK.
02 FILLER PIC X(30) VALUES ALL "*" .
02 FILLER PIC X(18) VALUES "-END OF CLIENT NO ".
02 CLIENT PIC 9.
02 FILLER PIC X VALUE "-".
02 FILLER PIC X(30) VALUES ALL "*" .
PROCEDURE DIVISION.
OPEN INPUT IN-FILE
OUTPUT OUT-FILE.
REPEAT-RTN.
ADD 1 TO CLIENT-NO.
MOVE CLIENT-NO TO CLIENT.
READ IN-FILE AT END PERFORM CLOSE-RTN.
MOVE CREDIT TO UNPAID-BAL.
MOVE MONTH TO CHECK-MONTH.
PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
COMPUTE CHECK-MONTH = CHECK-MONTH - 12
END-PERFORM.
COMPUTE CHECK-MONTH = MONTH + (12 - CHECK-MONTH).
MOVE ZEROES TO X.
PERFORM PROCESS-RTN CHECK-MONTH TIMES.
WRITE OUT-REC FROM PRINT-ASTERISK AFTER 1 LINE.
PERFORM REPEAT-RTN.
PROCESS-RTN.
ADD 1 TO X.
MOVE X TO REM.
PERFORM WITH TEST BEFORE UNTIL REM <= 13
COMPUTE REM = REM - 12
END-PERFORM.
IF REM=13 OR REM = 1 THEN
PERFORM HDG-RTN
END-IF.
IF REM=13 THEN
MOVE SPACES TO OUT-REC
WRITE OUT-REC.
MOVE X TO REC-MONTH.
COMPUTE INTEREST = UNPAID-BAL * 0.015.
COMPUTE TOTAL-PAY ROUNDED= CREDIT / MONTH + INTEREST.
COMPUTE UNPAID-BAL = UNPAID-BAL - TOTAL-PAY + INTEREST.
IF UNPAID-BAL < 1 THEN
MOVE ZEROES TO UNPAID-BAL
END-IF.
IF X > MONTH THEN
WRITE OUT-REC FROM PRINT-NULL AFTER 1 LINE
ELSE
MOVE TRANSFER-LINE TO PRINT-LINE
WRITE OUT-REC FROM PRINT-LINE AFTER 1 LINE
END-IF.
HDG-RTN.
IF X > 1 THEN
WRITE OUT-REC FROM HDG-01 AFTER 2 LINE
WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 2 LINE
ELSE IF CLIENT-NO > 1 THEN
WRITE OUT-REC FROM HDG-01 AFTER 1 LINE
WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 2 LINE
ELSE
WRITE OUT-REC FROM HDG-01 BEFORE 1 LINE
WRITE OUT-REC FROM HDG-02 BEFORE 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 1 LINE
END-IF.
WRITE OUT-REC FROM STREET AFTER 1 LINE.
WRITE OUT-REC FROM ZIP-CODE AFTER 1 LINES.
WRITE OUT-REC FROM HDG-03 AFTER 2 LINE.
MOVE CREDIT TO REC-CREDIT.
WRITE OUT-REC FROM HDG-04 AFTER 1 LINE.
WRITE OUT-REC FROM HDG-05 AFTER 2 LINE.
CLOSE-RTN.
CLOSE IN-FILE , OUT-FILE.
STOP RUN.
END PROGRAM MONTHLY.
该程序假设产生如下输出:
ABC Loans & Savings Company
Ayala Avenue, Makati City
The Client Name is Here:
The Client Address:
The ZiP/CITY:
SCHEDULE OF PAYMENTS
ORIGINAL AMOUNT 4291.50
MONTH INTEREST TOTAL-PAYMENT UNPAID-BALANCE
01 64.37 422.00 3933.87
02 05900 416.63 3576.24
03 05364 411.27 3218.61
04 04827 405.90 2860.98
05 04291 400.54 2503.35
06 03755 395.18 2145.72
07 03218 389.81 1788.09
08 02682 384.45 1430.46
09 02145 379.08 1072.83
10 01609 373.72 715.20
11 01072 368.35 357.57
12 00536 362.99 0.00
******************************-END OF CLIENT NO 1-******************************
但是我运行程序时的程序输出是不同的。它看起来像这样:
ABC Loans & Savings Company
Ayala Avenue, Makati City
The Client Name is Here:
The Client Address:
The ZiP/CITY:
SCHEDULE OF PAYMENTS
ORIGINAL AMOUNT 4291.50
MONTH INTEREST TOTAL-PAYMENT UNPAID-BALANCE
01 06437 00042200 00393387
02 05900 00041663 00357624
03 05364 00041127 00321861
04 04827 00040590 00286098
05 04291 00040054 00250335
06 03755 00039518 00214572
07 03218 00038981 00178809
08 02682 00038445 00143046
09 02145 00037908 00107283
10 01609 00037372 00071520
11 01072 00036835 00035757
12 00536 00036299 00000000
******************************-END OF CLIENT NO 1-******************************
我有关于小数格式和零抑制的问题。有什么建议吗?顺便说一句,我只是使用DAT文件作为我的输入,所以我不使用任何ACCEPT或输入函数,它包含一个记录所需的确切字符,如下文所示:
客户名称在此处:客户地址:ZiP / CITY:0042915012
我认为问题在于工作存储打印线和传输线。
答案 0 :(得分:4)
乍一看,我发现您的代码有两个问题:
PRINT-LINE
和TRANSFER-LINE
的长度不同,因为数字项的PICTURE
- 子句不同。例如,PRINT-LINE
使用PIC ZZ9.99
而TRANSFER-LINE
使用PIC 9(3)V99
。请注意,.
- 子句中的小数点PICTURE
需要一个字节的存储空间,而V
根本不需要任何存储空间,因此PRINT-LINE
中的字段是比TRANSFER-LINE
中的字节大一个字节。MOVE TRANSFER-LINE TO PRINT-LINE
时,您不会进行逐字段转移,而是将整个数据块移动为一个,因此PICTURE
中的PRINT-LINE
- 子句是完全被忽略了你不会遇到更大的麻烦,因为PRINT-LINE
比TRANSFER-LINE
占用更多的存储空间(参见1.) - 如果是相反的话,你甚至可能会遇到存储覆盖问题(但至少应该存在)得到编译器警告)。为了做到这一点你可以
PRINT-LINE
的02级项目命名为TRANSFER-LINE
,并执行MOVE CORRESPONDING TRANSFER-LINE TO PRINT-LINE
- 然后您必须使用限定名称({{1} }})或
INTEREST OF TRANSFER-LINE
并将您的数据直接放入TRANSFER-LINE
答案 1 :(得分:3)
@ piet.t指出了生成输出的问题。只有当单个字段是某个字段的“目标”字段时,才会发生任何类型的任何数据转换。对于将组移动到组,将忽略所有从属定义。
此外:
您对PERFORM进行“递归”使用。这样做是未定义的,并且可能因编译器而异。永远不要使用它。
您在FILE SECTION中的非88级项目上有一个VALUE子句。这没有任何作用 - 如果确实如此,你在尝试什么?
你的命名很差。 COBOL程序通常存在许多年。对于某些在20世纪70年代编写的程序,今天仍以100精度运行。一个程序将被编写一次,但需要多次理解 - 所以写给人们理解。不要使用单字名称,使用描述性名称(新的COBOL标准总是有可能“保留”您的单字名称,这将在下次程序更改时引起混淆)。 X,REM和CHECK-MONTH意味着什么? MONTH意味着什么(不是人们期望的那样)?
这是什么,它是堂兄,应该做什么?
PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
COMPUTE CHECK-MONTH = CHECK-MONTH - 12
END-PERFORM.
对于关注“古代”语言的人,为什么要键入所有那些句号/句号?自1985年以来,它们在如此广泛(且容易出错)的使用中并不需要它们。
使用END-IF。总是,不仅仅是在你想要的时候,结束每个IF。
使用评估。自1985年开始提供,并替换您的END-IF缺陷嵌套IF。
WITH TEST BEFORE是默认值。无需指定它。
如果没有签名,请考虑可能变为负数的字段不会这样做。
在编写程序之前设计程序。如果事实证明设计不起作用,请重新设计,而不是仅仅“修补”现有程序,使其看起来“有效”。
例如,知道您需要为每条记录添加标题,不是吗?为什么要在循环内测试?