Multiplication Table of a number - cobol

I'm totally new with COBOL. So can anyone help me with my code I want to print out the value of number X and the user should give this value. The Code should be:
"Please give a number FROM 1 TO 9"
For example number 7 will be given
the result must be
7 * 1 = 7
7 * 2 = 14
until
7 * 9 = 63
*****************************************************************
* Program name: MT01
* Original author: MYNAME
*
* Maintenance Log
* Date Author Maintenance Requirement
* --------- ------------ ---------------------------------------
* 01/01/08 MYNAME Created for COBOL class
*
*****************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. MT01.
AUTHOR. MYNAME.
INSTALLATION. COBOL DEVELOPMENT CENTER.
DATE-WRITTEN. 01/01/08.
DATE-COMPILED. 01/01/08.
SECURITY. NON-CONFIDENTIAL.
*****************************************************************
ENVIRONMENT DIVISION.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 X PIC 99.
01 INPUTT PIC 9.
01 RESULT PIC 9(3).
PROCEDURE DIVISION.
STEP0.
PERFORM STEP1.
PERFORM STEP2.
STEP1.
DISPLAY "Please give a number FROM 1 TO 9"
ACCEPT INPUTT.
STEP2.
MOVE 0 TO X
PERFORM VARYING X FROM 1 BY 1 UNTIL X > 12
END-PERFORM
GO TO STEP3.
STEP3.
COMPUTE RESULT = X * INPUTT
DISPLAY INPUTT " * " X " = " RESULT.
STOP RUN.
After applying the changes given by #Rick Smith, I compiled my PGM and got this MSG
MT01.cob:34: warning: inline PERFORM without imperative statement used [-Wdialect].
When I tried to execute ./MT01, nothing happened :(
The Code after editing
*****************************************************************
* Program name: MT01
* Original author: MYNAME
*
* Maintenence Log
* Date Author Maintenance Requirement
* --------- ------------ ---------------------------------------
* 01/01/08 MYNAME Created for COBOL class
*
*****************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. MT01.
AUTHOR. MYNAME.
INSTALLATION. COBOL DEVELOPMENT CENTER.
DATE-WRITTEN. 01/01/08.
DATE-COMPILED. 01/01/08.
SECURITY. NON-CONFIDENTIAL.
*****************************************************************
ENVIRONMENT DIVISION.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 X PIC 99.
01 INPUTT PIC 9.
01 RESULT PIC 9(3).
PROCEDURE DIVISION.
STEP0.
PERFORM STEP1.
PERFORM STEP2.
STOP RUN.
STEP1.
DISPLAY "Please give a number FROM 1 TO 9"
ACCEPT INPUTT.
STEP2.
PERFORM VARYING X FROM 1 BY 1 UNTIL X > 12
PERFORM STEP3
END-PERFORM.
STEP3.
COMPUTE RESULT = X * INPUTT
DISPLAY INPUTT " * " X " = " RESULT.

On the line after PERFORM STEP2., add either of the statements GOBACK. or STOP RUN.
Remove the line MOVE 0 TO X because X will be initialized to 1 in the following PERFORM statement.
Between the lines PERFORM VARYING ... and the END-PERFORM, add the line PERFORM STEP3. This will cause an output for each of the X values of 01 through 12.
Insert a . after the END-PERFORM and remove the GO TO STEP3. statement.
Remove the final STOP RUN. statement.
There is, apparently, a bug in the compiler. The updated code compiles and runs when checked for full ANSI COBOL 85 conformance on my Micro Focus compiler.
The problem appears to be that the imperative statement PERFORM STEP3 at line 29 is not being recognized as an imperative statement within the inline PERFORM.
The workaround is to change STEP2 to either of the following:
STEP2.
PERFORM STEP3 VARYING X FROM 1 BY 1 UNTIL X > 12.
STEP3.
COMPUTE RESULT = X * INPUTT
DISPLAY INPUTT " * " X " = " RESULT.
or
STEP2.
PERFORM VARYING X FROM 1 BY 1 UNTIL X > 12
COMPUTE RESULT = X * INPUTT
DISPLAY INPUTT " * " X " = " RESULT
END-PERFORM.
by replacing PERFORM STEP3 with the code from the STEP3 paragraph.

Related

Happy Numbers in COBOL

As the title implies, I'm doing a software that calculate and verify if the number inserted is a happy number (OR NOT). In COBOL language (For reference about what a happy number is https://mathworld.wolfram.com/HappyNumber.html).
Right now, my code doesnt calculate correctly if the number is happy or not (In the program HEY = Happy and HOY = not happy :C)
My question is, what am i doing wrong in the code? All i need now is to properly detect if its happy or not. Any help is well welcome.
This is my current code:
IDENTIFICATION DIVISION.
PROGRAM-ID. YOUR-PROGRAM-NAME.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 num PIC 9(36).
01 addc PIC 9(36).
01 rem PIC 9(36).
01 pow PIC 9(36).
01 toast PIC 9.
01 k PIC 999 VALUE 0.
01 l PIC 9(36).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
DISPLAY"Escribe numero "
ACCEPT num
PERFORM WITH TEST AFTER UNTIL addc = 1
MOVE 0 TO addc
PERFORM WITH TEST AFTER UNTIL num = 0
DIVIDE num BY 10 GIVING num REMAINDER rem
MULTIPLY rem BY rem GIVING pow
MOVE pow TO addc
END-PERFORM
IF addc = 1
MOVE 1 TO toast
ELSE
MOVE addc TO num
ADD 1 TO k
IF k = 20
MOVE 1 TO addc
MOVE 0 TO toast
END-IF
END-IF
END-PERFORM
IF toast = 1
DISPLAY "HEY"
ELSE
DISPLAY "HOY"
END-IF
STOP RUN.
END PROGRAM YOUR-PROGRAM-NAME.
Also, as an extra question, how can i handle numbers above the maximum limit of 36? without using the equivalent of strings and chars in Cobol.
The line:
PERFORM UNTIL num > 0
makes the PERFORM loop to not enter, as num is likely to be greater than 0. What you want to do is to execute the loop, getting all the digits from num UNTIL num is 0.
Besides,
MOVE pow TO addc
should be
ADD pow TO addc

Command Wait in COBOL?

Is there a kind of "Wait" function in COBOL?
I wrote a calculator, and to make it more 50s, i Print " Computing." "Computing.." ecc
For example:
DISPLAY "SECONDO NUMERO"
ACCEPT B
COMPUTE C= A * B
DISPLAY "Computing"
DISPLAY "Computing."
DISPLAY "Computing.."
DISPLAY "Computing..."
DISPLAY "Computing...."
DISPLAY "Computing....."
DISPLAY "Computing......"
DISPLAY A "x" B " FA..."
DISPLAY C
Now, is there a way to make a little delay (half a second) on COBOL where I put the "Computing" piece? I created a github repo (https://github.com/aIDserse/Super-utility-Submachine-COBOL-CALCULATOR) to this project, look at it (refer to version 1.3) for the complete code (and maybye spread it hahah). Thx!!!
There is a statement for sleeping in standard COBOL, but only with COBOL 202x:
CONTINUE AFTER arithmetic-expression SECONDS
As this standard is in the committee draft state it is hard to find an implementation, but as you've asked for GnuCOBOL - GnuCOBOL 3.1 already implements it.
Other than this there are some dialect specific library routines that can be used, like CALL "C$SLEEP" originating from ACUCOBOL-GT (also implemented with GnuCOBOL, but be aware that pre 3.1-versions only use the non-decimal part, so "0.9" will sleep zero seconds).
For OpenCOBOL/GnuCOBOL you can call the CBL_OC_NANOSLEEP/CBL_GC_NANOSLEEP library routines.
For any COBOL environment that can call native routines you have variants of CALL "sleep".
As mentioned by Rick Smith Many COBOL implementations also implement a callable SYSTEM where you may use something like a ping localhost with a timeout, but whatever you call may not be available (or the process running the COBOL environment has no access to it).
Stephen Gennard mentioned a very common extension:
ACCEPT something WITH TIMEOUT
which has a "beware" that different environments use a different scale (some seconds, some milliseconds). This has the pro/con that the user can "break" out by pressing a key (normally a function key); and the additional issue that it may only work in "graphical" environments.
Anton's answer highlights the IBM library routine CEE3DLY.
There's no wait statement in any ISO Standard COBOL.
However, if you got built in system routines available either C$SLEEP (for seconds) or CBL_GC_NANOSLEEP (for nanoseconds) should do the trick.
Example (sleeps for half a second):
call "CBL_GC_NANOSLEEP" using "500000000" end-call
For IBM's Enterprise COBOL (LE enabled) the CEE3DLY routine is most suitable (there are also other legacy routines available).
For GnuCobol call the C$SLEEP with the number of seconds you want to wait.
CALL "C$SLEEP" USING 2 END-CALL
COBOL has no build in language feature to handle waiting. This is a system specific request and I believe always requires calling an external module to interface with said system.
There is no wait or delay statement in standard COBOL. There may be, for GnuCOBOL, a CALL "SYSTEM" to effect a delay.
I took some code that I use for elapsed time measurement and modified the code to create a procedure for a delay.
Wherever you need a delay, insert the statement PERFORM timed-delay. Of course, the delay may be changed. This code is set to work even if the delay crosses midnight.
Code:
working-storage section.
01 t pic 9(8).
01 t-start.
03 t-start-hour pic 99.
03 t-start-minute pic 99.
03 t-start-second pic 99v99.
01 t-end.
03 t-end-hour pic 99.
03 t-end-minute pic 99.
03 t-end-second pic 99v99.
77 t-elapsed pic 9(7)v99.
procedure division.
begin.
accept t from time
display t
perform timed-delay
accept t from time
display t
stop run
.
timed-delay.
accept t-start from time
move 0 to t-elapsed
perform until t-elapsed > 0.5 *> one-half second
accept t-end from time
perform get-elapsed
end-perform
.
get-elapsed.
if t-start > t-end
move 86400 to t-elapsed
else
move 0 to t-elapsed
end-if
compute t-elapsed = t-elapsed
+ (t-end-hour - t-start-hour) * 3600
+ (t-end-minute - t-start-minute) * 60
+ (t-end-second - t-start-second)
end-compute
.
Output: (shows a delay of 0.55 seconds)
21424364
21424419
The initial PERFORM WITH TEST AFTER ... is nothing like the code I provided in: Cobol-Restart from the program , so I turned it into comments. It should be removed.
If you want to use SLEEP-SEC instead of a fixed value, replace the 0.5 with SLEEP-SEC; but provide a VALUE clause for SLEEP-SEC or MOVE a value to it before the displaying the menu.
For example, in your code (with most code removed):
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SLEEP-SEC PIC S9(2)V9(2).
01 A PIC S9(7)V9(7).
01 B PIC S9(7)V9(7).
01 C PIC S9(7)V9(7).
01 D PIC S9(11)V9(7).
01 INPUT1 PIC 9(14).
01 Q PIC X VALUE "Y".
01 t-start.
03 t-start-hour pic 99.
03 t-start-minute pic 99.
03 t-start-second pic 99v99.
01 t-end.
03 t-end-hour pic 99.
03 t-end-minute pic 99.
03 t-end-second pic 99v99.
77 t-elapsed pic 9(7)v99.
PROCEDURE DIVISION.
MAIN.
* PERFORM WITH TEST AFTER
* UNTIL Q ="YES" OR "Y" OR "y" OR "yes" OR "Yes"
* END-PERFORM.
DISPLAY "CALCULATOR".
DISPLAY "WHAT DO YOU WANT DO DO?".
DISPLAY "1 ADDITION".
DISPLAY "15 EXIT"
DISPLAY "CHOOSE AN OPTION"
ACCEPT INPUT1
EVALUATE INPUT1
WHEN = 15
DISPLAY "OK, GOOD JOB :)"
STOP RUN
WHEN = 1
DISPLAY "FIRST NUMBER"
ACCEPT A
DISPLAY "SECOND NUMBER"
ACCEPT B
COMPUTE C= A + B
DISPLAY "Computing"
PERFORM timed-delay
DISPLAY "(" A ")" "+" "(" B ")" "RESULTS..."
DISPLAY C
END-EVALUATE
IF INPUT1 NOT = 15
DISPLAY "DO YOU WANT TO DO OTHER CALCULATIONS?"
ACCEPT Q
IF Q = "YES" OR "Y" OR "y" OR "yes" OR "Yes" GO TO MAIN
ELSE DISPLAY "OK, GOOD JOB :)"
END-IF
STOP RUN.
timed-delay.
accept t-start from time
move 0 to t-elapsed
perform until t-elapsed > 0.5 *> one-half second
accept t-end from time
perform get-elapsed
end-perform
.
get-elapsed.
if t-start > t-end
move 86400 to t-elapsed
else
move 0 to t-elapsed
end-if
compute t-elapsed = t-elapsed
+ (t-end-hour - t-start-hour) * 3600
+ (t-end-minute - t-start-minute) * 60
+ (t-end-second - t-start-second)
end-compute
.

Cobol exponential with very high numbers: finding 5 ** 365 etc

** is used to compute exponentiation values in Cobol. That works OK with "small" numbers for example 5 ** 10 and so on.
Now there is a task where we should find X ** 365 + X ** 364 + X ** 363 + X ** 362 + X ** 361 + ... etc. where X is a decimal number with V9(02).
If ** is used with higher numbers for example 5.00 ** 41 then Truncation of high order digit positions occurs due to the fact that I'm able to keep PIC S9(29)V9(02) COMP-3 MAX (31 digits) with CBL ARITH(EXTEND) option.
Is there a work-around for this / Exponential function?
Is it possible at all on Cobol Enterprise for z/Os?
You could try something like this
The array "big-one" is like having a 1000 byte long numeric field.
i.e. pic 9(1000)
For "5 ** 365", you set mult to 5 and thymes to 365.
Since normal cobol won't support arithmetic on such large numbers, you have to do it yourself.
Start by setting big9(1000) to 1.
This is like having pic 9(1000) value 1.
Then loop "thymes" times thru paragraph "do-mult" that multiplies the digits of big-one by "mult', handling any "karry", by adding it to the intermediate result when calculating on the previous digit.
At the end, the digits of big-one represent the result.
IDENTIFICATION DIVISION.
PROGRAM-ID. cb043.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 sub1 pic 9(05).
01 big-one.
03 big9 occurs 1000 pic 9(01).
01 mult pic 9(06) value 5.
01 thymes pic 9(03) value 365.
01 sub2 pic 9(05).
01 sub3 pic 9(05).
01 interm pic 9(10).
01 filler redefines interm.
03 karry pic 9(09).
03 rite pic 9.
01 staw pic 9(09).
PROCEDURE DIVISION.
MAINLINE.
******* zeroise the big array
perform varying sub1
from 1 by 1
until sub1 > 1000
move 0 to big9(sub1)
end-perform.
******* make big-one like pic 9(1000) value 1
MOVE 1 to big9(1000).
******* do the multiplication "thymes" times
perform varying sub2
from 1 by 1
until sub2 > thymes
perform do-mult
end-perform.
******* find the first non-zero digit
perform varying sub1
from 1 by 1
until big9(sub1) not = 0
end-perform.
******* display the digits of the result
perform varying sub2
from sub1 by 1
until sub2 > 1000
display sub2 big9(sub2)
end-perform.
stop run.
do-mult.
******* zeroise the stored carry field, "staw"
move 0 to staw.
******* multiply every digit of "big-one"
******* starting at big9(1000) and working backwards to big9(1)
******* the left hand 9 bytes of "interm", represent any carry, as "karry"
******* which is stored in "staw" and is added when the next calculation is
******* done
perform varying sub3
from 1000 by -1
until sub3 = 0
compute interm = (big9(sub3) * mult)
+ staw
move karry to staw
move rite to big9(sub3)
end-perform.
Some problems:
First, 5 ** 365 requires 255 digits.
Second pic S9(29)V9(02) requires that x be somewhat less than 1.2.
However, x is defined as V9(02) (unless something more was intended). The "work-around" is logarithms. FUNCTION LOG10 is available in Enterprise COBOL.
identification division.
program-id. big-exp.
data division.
1 x binary pic v99 value 0.99.
1 log10-of-x comp-2.
1 value-of-x-to-n comp-2.
1 sum-of-values comp-2 value 0.
1 disp-sum pic z(3).9(15).
1 n binary pic 9(3).
procedure division.
begin.
compute log10-of-x = function log10 (x)
perform varying n from 365 by -1
until n = 0
compute value-of-x-to-n = 10 ** (log10-of-x * n)
compute sum-of-values = sum-of-values +
value-of-x-to-n
end-perform
move sum-of-values to disp-sum
display disp-sum
stop run
.
For x = 0.99 the answer is approximately 96.473721519223000.
But note that as x drops below approximately 0.10, underflow may occur.

Income Tax Logic Questions

I'm having some trouble figuring out the logic behind this.
I need to display a report calculating balance, interest and principal per month until the balance is zero.
As an example, if input is months=12, balance=25000, rate=4.5%, output should look like this:
months balance interest principal
1 $25000.00 $93.75 $2,040.71
2 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
I'm not sure what to write after DISPLAY col-hdr and before STOP RUN. Any ideas?
IDENTIFICATION DIVISION.
PROGRAM-ID. practice.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LOANFMT PIC $$$$,$$$,$$$.$$.
01 LOANAMT PIC S9(9)V9(2) VALUE 0.
01 INTRATE PIC S9V9(2) VALUE 0.
01 INTFMT PIC 9.999.
01 NUMMONTHS PIC S9(3) VALUE 0.
01 MONFMT PIC ZZ9.
01 MONCNT PIC S999 VALUE 1.
01 PMT PIC S9(9)V9(2) VALUE 0.
01 PMTFMT PIC $$$$,$$$,$$$.$9.
01 TOTPMT PIC S9(9)V9(2) VALUE 0.
01 TOTFMT PIC $$$$,$$$,$$$.$9.
01 col-hdr.
05 pic x(15) value "Month".
05 pic x(15) value "Balance".
05 pic x(15) value "Interest".
05 pic x(15) value "Principal".
01 Detail-Line.
05 Pic X(2) Value Spaces.
05 DL-MONTH Pic X(999) VALUE 1.
05 Pic X(5) Value Spaces.
05 DL-BALANCE Pic $$$$,$$$,$$$.$9.
05 Pic X(4) Value Spaces.
05 DL-INTEREST Pic $$$$,$$$,$$$.$9.
05 Pic X(4) Value Spaces.
05 DL-PRINCIPAL Pic $$$$,$$$,$$$.$9.
PROCEDURE DIVISION.
000-MAIN SECTION.
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
IF 0 > LOANAMT
PERFORM UNTIL LOANAMT > 0
DISPLAY "Loan Amount must be positive"
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
end-PERFORM
END-IF
DISPLAY "Enter Annual Interest Rate: " WITH NO ADVANCING
ACCEPT INTRATE
IF 0 > INTRATE
PERFORM UNTIL INTRATE > 0
DISPLAY "Annual Interest Rate must be positive"
DISPLAY "Enter Annual Interest Rate: " WITH
NO ADVANCING
ACCEPT INTRATE
end-PERFORM
END-IF
DISPLAY "Enter Number of Months: " WITH NO ADVANCING
ACCEPT NUMMONTHS
IF 0 > NUMMONTHS
PERFORM UNTIL NUMMONTHS > 0
DISPLAY "Number of Months must be positive"
DISPLAY "Enter Number of Months: " WITH NO
ADVANCING
ACCEPT NUMMONTHS
end-PERFORM
END-IF
DISPLAY SPACE
move LOANAMT TO LOANFMT
move INTRATE TO INTFMT
MOVE NUMMONTHS TO MONFMT
MOVE PMT TO PMTFMT
MOVE TOTPMT TO TOTFMT
DISPLAY col-hdr
100-init.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE
PERFORM 200-ADDMONTH UNTIL NUMMONTHS = DL-MONTH
200-ADDMONTH.
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE - DL-PRINCIPAL
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE.
STOP RUN.
months balance interest principal
1 $25000.00 $93.75 $2,040.71
2 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
Firstly, get that sorted out.
months balance interest principal
01 $25,000.00 $93.75 $2,040.71
02 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
That looks much more professional, and easy to produce. I don't like the "months" heading, because it is not clear what it means. Some capitalisation would be good as well, but those are up to you. Actual spacing you can sort out as well. In my experience, Principal would always be before Interest, and a figure of the Payment before that. The user will want to see the Payment, not have to work it out, and want to confirm the split of the payment, and visually verify the interest amount.
Maybe it's regional, however.
As Brian noted in a comment, you've had you elbow on the 9 key whilst defining the month in the detail line. Make it PIC 99 or PIC Z9.
You are writing your program as a "fall through" structure. Perhaps that is what you are used to with other languages. Mainly COBOL programs that you would see would have a different structure.
Here is your code re-arranged, also with attention paid to indentation, which is important for the human reader. The spacing I find useful, but is not as mandatory as the indentation:
PROCEDURE DIVISION.
PERFORM GET-AND-VALIDATE-USER-INPUT
PERFORM PROCESS-USER-INPUT
PERFORM PRODUCE-REPORT
GOBACK
.
GET-AND-VALIDATE-USER-INPUT.
PERFORM GET-AND-VALIDATE-LOAN-AMT
PERFORM GET-AND-VALIDATE-INT-RATE
PERFORM GET-AND-VALIDATE-MONTHS
.
GET-AND-VALIDATE-LOAN-AMT.
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
IF 0 > LOANAMT
PERFORM UNTIL LOANAMT > 0
DISPLAY "Loan Amount must be positive"
DISPLAY "Enter Loan Amount: "
WITH NO ADVANCING
ACCEPT LOANAMT
end-PERFORM
END-IF
.
GET-AND-VALIDATE-INT-RATE.
DISPLAY "Enter Annual Interest Rate: " WITH NO ADVANCING
ACCEPT INTRATE
IF 0 > INTRATE
PERFORM UNTIL INTRATE > 0
DISPLAY "Annual Interest Rate must be positive"
DISPLAY "Enter Annual Interest Rate: "
WITH NO ADVANCING
ACCEPT INTRATE
end-PERFORM
END-IF
.
GET-AND-VALIDATE-MONTHS.
DISPLAY "Enter Number of Months: " WITH NO ADVANCING
ACCEPT NUMMONTHS
IF 0 > NUMMONTHS
PERFORM UNTIL NUMMONTHS > 0
DISPLAY "Number of Months must be positive"
DISPLAY "Enter Number of Months: "
WITH NO ADVANCING
ACCEPT NUMMONTHS
end-PERFORM
END-IF
.
PROCESS-USER-INPUT.
PERFORM GET-AND-VALIDATE-MONTHS
move LOANAMT TO LOANFMT
move INTRATE TO INTFMT
MOVE NUMMONTHS TO MONFMT
MOVE PMT TO PMTFMT
MOVE TOTPMT TO TOTFMT
.
PRODUCE-REPORT.
DISPLAY SPACE [don't know what you want that for]
DISPLAY col-hdr
PERFORM FORMAT-INITIAL-LINE
PERFORM OUTPUT-DETAIL-LINE
PERFORM FORMAT-MONTHS-TO-END
.
FORMAT-INITIAL-LINE.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
DL-PRINCIPAL = LOANAMT
- DL-INTEREST
.
OUTPUT-DETAIL-LINE.
DISPLAY DETAIL-LINE
.
FORMAT-MONTHS-TO-END.
PERFORM NUMMONTHS = DL-MONTH
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE
- DL-PRINCIPAL
DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
DL-PRINCIPAL = LOANAMT
- DL-INTEREST
PERFORM OUTPUT-DETAIL-LINE
END-PERFORM
.
You have assignments. COBOL does not. COBOL has COMPUTE, so you'll need to use that, although MOVE, ADD, SUBTRACT, DIVIDE and MULTIPLY can clarify as well:
FORMAT-INITIAL-LINE.
MOVE LOANAMT TO DL-BALANCE
COMPUTE DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
SUBTRACT DL-INTEREST FROM LOANAMT
GIVING DL-PRINCIPAL
.
Note that GIVING. SUBTRACT A FROM B will change the value of B. If you put GIVING C on the end, B will no longer be changed, instead the result will be placed in C. ADD A TO B changes B. ADD A B GIVING C does not (note this time no need for TO, although syntactically it can be there). Ensure you understand what ADD, SUBTRACT, MULTIPLY and DIVIDE can do.
It is possible to only use COMPUTE. Unlike myth, there is no performance penalty in this, but extra human-reader information is lost.
With modern COBOL compilers it is not necessary to start a program with an arbitrary procedure name (either SECTION or paragraph). It has no meaning, at all. So ditch this (unless dictated by tutor/site-standards):
000-MAIN SECTION.
You have things like this:
IF 0 > LOANAMT
And:
PERFORM UNTIL LOANAMT > 0
I understand the point made by cshneid made in a comment, but there is consistency, and there is the fact that COBOL has no assignment statement. An expression in a conditional construct can never cause a change to any field involved in the expression.
IF LOANAMT > 0
Or:
IF LOANAMT GREATER THAN 0
Can be read, by the mythical average COBOL programmer, without pause.
IF 0 < LOANAMT
Is more of a discontinuity. The reader has to stop and think what that means. There is no benefit in doing it that way, and there are disbenefits.
DISPLAY and ACCEPT are the COBOL verbs which vary the most from the COBOL standard, from compiler to compiler. To the COBOL 85 Standard, ACCEPT and DISPLAY are very plain. You are using a compiler with "Extended" ACCEPT and DISPLAY. This may (probably does) allow the entry of negative amounts, and may prevent the entry of non-numeric data, but you need to check the documentation for your compiler. It will be important that the data entered is numeric. It is easier to get a character in the number than to enter a negative value by accident.
From your original code:
100-init.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE
PERFORM 200-ADDMONTH UNTIL NUMMONTHS = DL-MONTH
200-ADDMONTH.
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE - DL-PRINCIPAL
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE.
STOP RUN.
Here, since 100-init is not PERFORMed, the program control will drop through into 200-ADDMONTH. Labels (paragraphs or SECTIONs) are just labels. They can be the target of a PERFORM, a GO TO, or they can be "fallen through" or "dropped into". They are unlike "subroutine" or "function" definitions in other languages you probably know.
So, 100-init will PERFORM 200-ADDMONTH until it is finished with, then it will fall into 200-ADDMONTH again. Never code that deliberately. Each paragraph/SECTION should be self-contained and not rely on the physical location of its content.
If 100-init were PERFORMed, you'd be OK. Sort of. Because you have a STOP RUN in 200-ADDMONTH. When 200-ADDMONTH is executed the first time, the program will stop executing. Not what you want.
I've not considered the logic of your actual calculation, just the methods of it. You have duplicated code, so that could go in another PERFORMed paragraph/SECTION.
Be aware of the difference between a paragraph and a SECTION when they are PERFORMed. A SECTION can (these days does not have to) contain paragraphs. When a SECTION is PERFORMed, control returns to the completed PERFORM before the next SECTION. When a paragraph is PERFORMed, control returns before the next paragraph. Paragraphs cannot contain other paragraphs. To PERFORM a range of paragraphs, THRU will be required on the PERFORM. Unless dictated by tutor/site-standards, avoid coding that. Again, it relies on the physical location of code. Which is bad.
These days, there should be no intrinsic need for SECTIONs, and no need (except diktat) for PERFORM ... THRU ....

Temperature converter doesn't return correct value

IDENTIFICATION DIVISION.
PROGRAM-ID. TEMP1 .
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-A PIC 9(2).
01 WS-B PIC 9(2).
PROCEDURE DIVISION.
ACCEPT WS-A.
COMPUTE WS-B ROUNDED = ( ( 9 / 5 ) * WS-A ) + 32.
DISPLAY WS-B.
STOP RUN.
This is my program for accepting temperature in Celcius and converting it to Fahrenheit. I have created a LOADLIB and a COPYLIB. Also one JCL for compilation and RUNJCL. No error is coming, but when I give any input (e.g. 98) in RUNJCL, it always shows 32 as output. What is the problem?
If the result you are getting is always 32, then WS-A is zero, because something multiplied by zero and adding 32 will always be 32.
I suspect that you have in your JCL something like this:
//SYSIN DD *
00212
When you do the ACCEPT, you will only get 00 from that.
When using ACCEPT for little testing programs it is a good idea to DISPLAY what you get, so you can see.
Either make WS-A larger, or the value on the card following your SYSIN smaller.
It if also possible you have other problems causing the value of WS-A to be treated as zero. So, can you paste the JCL from file 2 on the spool for your JOB. With the line-numbers it generated :-)
And the SYSIN card data (your 98). Look out particularly for any "SYSIN generated" statements in your JCL output.
Here's your program. I've got rid of unnecessary things, and changed the names of WS-A and WS-B. Now that WS-B has a proper name, you can see as you create it that it is the wrong length, it needs to be at least three digits.
ID DIVISION.
PROGRAM-ID. TEMP1.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 INPUT-CENTIGRADE PIC 9(2).
01 OUTPUT-FARENHEIT PIC 9(3).
PROCEDURE DIVISION.
ACCEPT INPUT-CENTIGRADE
DISPLAY
"CELSIUS COMING IN "
">"
INPUT-CENTIGRADE
"<"
COMPUTE OUTPUT-FARENHEIT ROUNDED
= ( ( 9 / 5 )
* INPUT-CENTIGRADE )
+ 32
DISPLAY
"FARENHEIT GOING OUT "
">"
OUTPUT-FARENHEIT
"<"
GOBACK
.
The output from running the program is:
CELSIUS COMING IN >98<
FARENHEIT GOING OUT >208<
Running this version of your program with "0098" for input gives this:
CELSIUS COMING IN >00<
FARENHEIT GOING OUT >032<

Resources