I'm still working with Cobol:)
I have a question, let's take this code:
ACCEPT A
COMPUTE C= FUNCTION SIN(A)
END-COMPUTE
DISPLAY "Computing."
DISPLAY "Computing.."
DISPLAY "Computing..."
DISPLAY "Computing...."
DISPLAY "Computing....."
DISPLAY "Computing......"
DISPLAY "IL SENO DI " A " RISULTA..."
DISPLAY C " GRADI"
Now, it does Sinus, but the outup is, for example with 37: 00000000000000 GRADI
My Scientific Calculator says: 0.6018
As you see COBOL does not show the numbers after comma. Is there a way to show them? Thank you:)
Building on what Rick and RB123 have told you already here's what I see is the answer. The correct way to picture a data item that has a decimal place is with a V showing the position of the implied point and not with a '.' which controls the position the decimal is display at only in an edited output field. The main difference is that you can input or compute on fields with a 'V' and only display or output fields with a '.'
PS. I'm in the US where the decimal point is '.' - some contries use a comma instead. This can be changed by using the DECIMAL-POINT IS COMMA special name.
IDENTIFICATION DIVISION.
PROGRAM-ID. Decimals.
ENVIRONMENT DIVISION.
* CONFIGURATION SECTION.
* SPECIAL-NAMES.
* DECIMAL-POINT IS COMMA.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 A pic S9(2)V9(5) comp-3.
01 C pic S9(2)V9(5) comp-3.
PROCEDURE DIVISION.
BEGIN.
ACCEPT A
COMPUTE C = FUNCTION SIN(A * 3.14159 / 180)
DISPLAY "Computing."
DISPLAY "Computing.."
DISPLAY "Computing..."
DISPLAY "Computing...."
DISPLAY "Computing....."
DISPLAY "Computing......"
DISPLAY "IL SENO DI " A " RISULTA..."
DISPLAY C " GRADI"
GOBACK.
My cobol is not gnu, but you can do something like
01 C comp-2.
01 A pic 999.
01 C1 pic 999.999999.
PROCEDURE DIVISION.
BEGIN.
move 37 to A
COMPUTE C = FUNCTION SIN(A)
END-COMPUTE
move C to C1
DISPLAY "Computing."
DISPLAY "Computing.."
DISPLAY "Computing..."
DISPLAY "Computing...."
DISPLAY "Computing....."
DISPLAY "Computing......"
DISPLAY "IL SENO DI " A " RISULTA..."
DISPLAY C1 " GRADI"
The actual output is
Computing.
Computing..
Computing...
Computing....
Computing.....
Computing......
IL SENO DI 037 RISULTA...
000.643538 GRADI
Related
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
.
I'm learning about cobol alone and when I was coding my first code I had some doubts.
I'm using GnuCOBOL v2.2 at websites (TutorialsPoint and JDoodle) and I didn't understand how I can put inputs by comand window. Do anyone know how do it at these websites ?
Other thing is about how to clean terminal, when I use "DISPLAY WINDOW ERASE" I have that error message: "140: warning: GRAPHICAL WINDOW is not implemented". Do I need to use any library or exist any other comand ?
One more doubt: function integer-of-date do not convert that it proposes, the output is coming zero just. Code is below:
WORKING-STORAGE SECTION.
77 DATA1 PIC 9(006).
77 DATA2 PIC 9(006).
77 INTEIRO-1 PIC 9(008).
77 INTEIRO-2 PIC 9(008).
77 DIAS PIC 9(005).
PROCEDURE DIVISION.
ACCEPT DATA1 FROM DATE
SET DATA2 TO 930217
MOVE FUNCTION INTEGER-OF-DATE (DATA1) TO INTEIRO-1 *> wrong convertion?
MOVE FUNCTION INTEGER-OF-DATE (DATA2) TO INTEIRO-2
COMPUTE DIAS = INTEIRO-2 - INTEIRO-1
DISPLAY X"0A"DATA1 " " DATA2
SET INTEIRO-1 TO FUNCTION INTEGER-OF-DATE(DATA1)
DISPLAY INTEIRO-1 " " INTEIRO-2
DISPLAY "DIAS: " DIAS
The output of that code is:
180516 930217
00000000 00000000
DIAS: 00000
Answering the integer-of-date question
FUNCTION INTEGER-OF-DATE(ccyymmdd)
You need to use full 4 digit years in a PIC 9(8) field for this function.
ACCEPT FROM DATE returns a PIC 9(6), and there is now an
ACCEPT FROM DATE YYYYMMDD form that returns a PIC 9(8).
The INTEGER-OF-DATE() intrinsic function takes a date in 8 digits format (YYYYMMDD). You could use FUNCTION CURRENT-DATE to get an 8 digit date.
The syntax SET datum TO value is normally reserved for indices, for general data you should use MOVE value TO datum.
I am trying to access the same file to do two certain tasks. The first task is to update, add, and delete records. Access has to be random. The second task is to display all records on console. Access has to be sequential. I receive code 65 File locked from COBOL because the program is trying to access the same file twice the same time. Is there any way to fix this error? Or is there an different way to do this? Or do I have to write a separate program to display the record on console? I am stuck!
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT MAST-FILE ASSIGN TO 'G:\CPSC315-COBOL\COBOLAssignments\P15-5\SALES.IND.TXT'
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY M-SALESPERSON-NUM.
SELECT MAST2-FILE ASSIGN TO 'G:\CPSC315-COBOL\COBOLAssignments\P15-5\SALES.IND.TXT'
ORGANIZATION IS INDEXED
ACCESS IS SEQUENTIAL
RECORD KEY M2-SALESPERSON-NUM.
DATA DIVISION.
FILE SECTION.
FD MAST-FILE
LABEL RECORDS ARE STANDARD.
01 MAST-RECORD.
05 M-SALESPERSON-NUM PIC XXX.
05 M-CUSTOMER-NAME PIC X(15).
05 M-TOTAL-SALES PIC 9(5)V99.
05 M-COST-OF-SALES PIC 9(4)V99.
FD MAST2-FILE
LABEL RECORDS ARE STANDARD.
01 MAST2-RECORD.
05 M2-SALESPERSON-NUM PIC X(3).
05 M2-SALESPERSON-NAME PIC X(15).
05 M2-TOTAL-SALES PIC 9(5)V99.
05 M2-COST-OF-SALES PIC 9(4)V99.
WORKING-STORAGE SECTION.
01 SALES-DATA.
05 SALESPERSON-NUM PIC X(3).
05 SALESPERSON-NAME PIC X(15).
05 TOTAL-SALES PIC 9(5)V99.
05 COST-OF-SALES PIC 9(4)V99.
01 OUTPUT-RECORD.
05 PIC X(1) VALUE SPACES.
05 O-SALESPERSON-NUM PIC X(3).
05 PIC X(3) VALUE SPACES.
05 O-SALESPERSON-NAME PIC X(3).
05 PIC X(3) VALUE SPACES.
05 O-TOTAL-SALES PIC 9(5)V99.
05 PIC X(3) VALUE SPACES.
05 O-COST-OF-SALES PIC 9(4)V99.
01 PROGRAM-DATA-ITEMS.
05 I-SALESPERSON-NUM PIC XXX.
05 WAIT-OK PIC X.
05 CHOICE PIC 9 VALUE 0.
05 READ-OK PIC X.
05 REWRITE-OK PIC X.
05 DELETE-OK PIC X.
PROCEDURE DIVISION.
10-MAINLINE.
OPEN I-O MAST-FILE
OPEN INPUT MAST2-FILE
PERFORM 20-PROCESS-LOOP
CLOSE MAST-FILE
MAST2-FILE
STOP RUN.
20-PROCESS-LOOP.
PERFORM UNTIL CHOICE = 5
PERFORM 30-DISPLAY-MENU
EVALUATE CHOICE
WHEN 1
PERFORM 40-UPD-SALES
WHEN 2
PERFORM 90-ADD-SALES
WHEN 3
PERFORM 110-DELETE-SALES
WHEN 4
PERFORM 120-DISPLAY-SALES
END-EVALUATE
END-PERFORM.
30-DISPLAY-MENU.
DISPLAY 'SALES MAINTENANCE SYSTEM'
DISPLAY ' '
DISPLAY ' SELECT ONE:'
DISPLAY ' '
DISPLAY ' 1. UPDATE SALES RECORD'
DISPLAY ' 2. ADD SALES RECORD'
DISPLAY ' 3. DELETE SALES RECORD'
DISPLAY ' 4. DISPLAY SALES RECORD'
DISPLAY ' 5. QUIT'
DISPLAY ' '
DISPLAY 'ENTER CHOICE (1 - 5): ' WITH NO ADVANCING
ACCEPT CHOICE
PERFORM UNTIL CHOICE >= 1 AND <= 5
DISPLAY ' '
DISPLAY 'ERROR: ENTER CHOICE (1 - 5): ' WITH NO ADVANCING
ACCEPT CHOICE
END-PERFORM.
40-UPD-SALES.
DISPLAY 'UPDATE SALES: ENTER SALESPERSON NUMBER: ' WITH NO ADVANCING
ACCEPT SALESPERSON-NUM
MOVE SALESPERSON-NUM TO M-SALESPERSON-NUM
PERFORM 50-READ-RECORD
IF READ-OK = 'N'
DISPLAY 'RECORD DOES NOT EXIST - PRESS ENTER'
ACCEPT WAIT-OK
ELSE
DISPLAY SALES-DATA
PERFORM 100-INPUT-NEW-RECORD
PERFORM 60-REWRITE-RECORD
END-IF.
50-READ-RECORD.
MOVE 'Y' TO READ-OK
READ MAST-FILE INTO SALES-DATA
INVALID KEY
MOVE 'N' TO READ-OK
END-READ.
60-REWRITE-RECORD.
REWRITE MAST-RECORD FROM SALES-DATA
INVALID KEY
DISPLAY 'REWRITE ERROR: SALESPERSON NUMBER ' SALESPERSON-NUM
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-REWRITE.
70-WRITE-RECORD.
MOVE 'Y' TO REWRITE-OK
WRITE MAST-RECORD FROM SALES-DATA
INVALID KEY
MOVE 'N' TO REWRITE-OK
END-WRITE
IF REWRITE-OK = 'N'
DISPLAY 'WRITE ERROR: SALESPERSON NUMBER ' SALESPERSON-NUM
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-IF.
80-DELETE-RECORD.
MOVE 'Y' TO DELETE-OK
DELETE MAST-FILE
INVALID KEY
MOVE 'N' TO DELETE-OK
END-DELETE
IF REWRITE-OK = 'N'
DISPLAY 'WRITE ERROR: SALESPERSON NUMBER ' SALESPERSON-NUM
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-IF.
90-ADD-SALES.
DISPLAY 'ADD SALES RECORD: ENTER SALESPERSON NUMBER: ' WITH NO ADVANCING
ACCEPT SALESPERSON-NUM
MOVE SALESPERSON-NUM TO M-SALESPERSON-NUM
PERFORM 50-READ-RECORD
IF READ-OK = 'Y'
DISPLAY 'RECORD ALREADY EXISTS - PRESS ENTER'
ACCEPT WAIT-OK
ELSE
PERFORM 100-INPUT-NEW-RECORD
PERFORM 70-WRITE-RECORD
IF REWRITE-OK = 'Y'
DISPLAY 'RECORD ' SALESPERSON-NUM ' ADDED TO FILE'
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-IF
END-IF.
100-INPUT-NEW-RECORD.
MOVE SALESPERSON-NUM TO M-SALESPERSON-NUM
DISPLAY ' ENTER SALESPERSON NAME: ' WITH NO ADVANCING
ACCEPT SALESPERSON-NAME
DISPLAY ' ENTER TOTAL SALES: ' WITH NO ADVANCING
ACCEPT TOTAL-SALES
DISPLAY ' ENTER COST OF SALES: ' WITH NO ADVANCING
ACCEPT COST-OF-SALES.
110-DELETE-SALES.
DISPLAY 'DELETE SALES RECORD: ENTER SALESPERSON NUMBER: ' WITH NO ADVANCING
ACCEPT SALESPERSON-NUM
MOVE SALESPERSON-NUM TO M-SALESPERSON-NUM
PERFORM 50-READ-RECORD
IF READ-OK = 'N'
DISPLAY 'RECORD DOES NOT EXIST - PRESS ENTER'
ACCEPT WAIT-OK
ELSE
PERFORM 80-DELETE-RECORD
IF DELETE-OK = 'Y'
DISPLAY 'RECORD DELETED - PRESS ENTER'
ACCEPT WAIT-OK
END-IF
END-IF.
120-DISPLAY-SALES.
MOVE SALESPERSON-NUM TO M2-SALESPERSON-NUM
MOVE SALESPERSON-NAME TO M2-SALESPERSON-NAME
MOVE TOTAL-SALES TO M2-TOTAL-SALES
MOVE COST-OF-SALES TO M2-COST-OF-SALES
READ MAST2-FILE
AT END MOVE HIGH-VALUES TO M2-SALESPERSON-NUM
END-READ
PERFORM UNTIL M2-SALESPERSON-NUM = HIGH-VALUES
MOVE M2-SALESPERSON-NUM TO O-SALESPERSON-NUM
MOVE M2-SALESPERSON-NAME TO O-SALESPERSON-NAME
MOVE M2-TOTAL-SALES TO O-TOTAL-SALES
MOVE M2-COST-OF-SALES TO O-COST-OF-SALES
DISPLAY OUTPUT-RECORD
READ MAST2-FILE
AT END MOVE HIGH-VALUES TO M2-SALESPERSON-NUM
END-READ
END-PERFORM.
end program Program1.
When you open a file I-O, that means you open it for Input and Output. Get rid of your second file.
To position your file for displaying the data, you can READ with a KEY and then READ ... NEXT ..., or you can use START ... and then READ ... NEXT.
Always use the FILE STATUS in the ASSIGN. Then use the file-status field you tell COBOL to put the file status in to, to check the previous IO. Use it for end-of-file (value of "10"). Use 88s. You don't then need the INVALID KEY and AT END and all the END- statements associated with IO can go, because you then don't have a built-in condition with the IO. Which will simplify things.
Your structure is very good for a beginner. Refreshing to see no PERFORM ... THRU ....
I'd suggest you try the effect of a single full-stop/period in column 12 on a line of its own. You'll then be able to move the last line of code from a paragraph without having to think about the full-stop/period attached to it (because it isn't attached to it).
Use more PERFORMs. OPEN and CLOSE are not vital to the logic of the program. Hide them away in paragraphs, do the FILE STATUS checking on them. Same with the READ/WRITE/DELETE and any other IO statements you end up with. Hide them in well-named procedures which you PERFORM.
Consider the size (number of lines) of some of your IFs. Put the code in a well-named procedure, and the code can be "read" at a high level by a human, with the detail only being looked at if needed.
Do not, do not, do not, mess around with two files. Do not, do not, do not OPEN the same file twice (I've written a few COBOL programs in my time, and I've never, ever, considered that a reasonable way to achieve anything, let alone the simple task you have).
You may want to consider DYNAMIC instead of RANDOM (this is what it is for). You use RANDOM if you are only doing random access. You actually want to do sequential access as well (look for references to skip-sequential access for further discussion).
SELECT MAST-FILE ASSIGN TO 'G:\CPSC315-COBOL\COBOLAssignments\P15-5\SALES.IND.TXT'
ORGANIZATION IS INDEXED
ACCESS IS RANDOMREWRITE-OK = 'N'
RECORD KEY M-SALESPERSON-NUM
FILE STATUS IS W-MAST-FILE-STATUS.
...
01 W-MAST-FILE-STATUS PIC XX.
88 W-MAST-FILE-LAST-IO-OK VALUE "00".
88 W-MAST-FILE-EOF VALUE "10".
88 W-MAST-FILE-REC-NOT-FOUND VALUE "23".
88 W-MAST-FILE-OR-OR-NOT-FOUND VALUE "00" "23".
...
50-READ-RECORD.
MOVE 'Y' TO READ-OK
READ MAST-FILE INTO SALES-DATA
INVALID KEY
MOVE 'N' TO READ-OK
END-READ.
Becomes:
50-READ-RECORD.
READ MAST-FILE KEY key-name INTO SALES-DATA
IF NOT ( W-MAST-FILE-OR-OR-NOT-FOUND )
some code to deal with the pickle, which is nothing to do with
business-logic, so hide it away
END-IF
.
80-DELETE-RECORD.
MOVE 'Y' TO DELETE-OK
DELETE MAST-FILE
INVALID KEY
MOVE 'N' TO DELETE-OK
END-DELETE
IF REWRITE-OK = 'N'
DISPLAY 'WRITE ERROR: SALESPERSON NUMBER ' SALESPERSON-NUM
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-IF.
Becomes:
80-DELETE-RECORD.
DELETE MAST-FILE
IF NOT W-MAST-FILE-LAST-IO-OK
DISPLAY 'WRITE ERROR: SALESPERSON NUMBER ' SALESPERSON-NUM
DISPLAY 'PRESS ENTER TO CONTINUE'
ACCEPT WAIT-OK
END-IF
.
Each IO paragraph becomes self-contained, self-verifying, and the FILE STATUS field naturally bears only good conditions when you are in your business logic. The "can't happen" (but will, one day) you deal with in these paragraphs.
You code elsewhere simplifies. Your number of "flags" is reduced (the value of the FILE STATUS field replaces the need for the flags) your IOs have no conditional part, so don't need the END- scope delimiter.
A tip about numbering paragraphs. Don't do it until you have tested sufficiently that you are happy with the structure of the logic. Once you are happy with that, rearrange the paragraphs so that the paragraph is always physically after the PERFORM of it. Then put the numbers on. The physical layout of your code then represents the structure of your program logic.
If you number first, you'll end up with the situation you have - you have numbers, but they infer nothing. It is much more tedious to "renumber" paragraphs than it is to add paragraph numbers where there were none (use the power of the editor/utilities available to you to do this numbering).
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<
I'm just learning COBOL; I'm writing a program that simply echos back user input. I have defined a variable as:
User-Input PIC X(30).
Later when I ACCEPT User-Input, then DISPLAY User-Input " plus some extra text", it has a bunch of spaces to fill the 30 characters. Is there a standard way (like Ruby's str.strip!) to remove the extra spaces?
One would hope for a more elegant way of simply trimming text strings
but this is pretty much the standard solution... The trimming part
is done in the SHOW-TEXT paragraph.
*************************************
* TRIM A STRING... THE HARD WAY...
*************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. TESTX.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 USER-INPUT PIC X(30).
01 I PIC S9(4) BINARY.
PROCEDURE DIVISION.
MOVE SPACES TO USER-INPUT
PERFORM SHOW-TEXT
MOVE ' A B C' TO USER-INPUT
PERFORM SHOW-TEXT
MOVE 'USE ALL 30 CHARACTERS -------X' TO USER-INPUT
PERFORM SHOW-TEXT
GOBACK
.
SHOW-TEXT.
PERFORM VARYING I FROM LENGTH OF USER-INPUT BY -1
UNTIL I LESS THAN 1 OR USER-INPUT(I:1) NOT = ' '
END-PERFORM
IF I > ZERO
DISPLAY USER-INPUT(1:I) '# OTHER STUFF'
ELSE
DISPLAY '# OTHER STUFF'
END-IF
.
Produces the following output:
# OTHER STUFF
A B C# OTHER STUFF
USE ALL 30 CHARACTERS -------X# OTHER STUFF
Note that the PERFORM VARYING statement relies on the left to
right evaluation of the UNTIL clause to avoid out-of-bounds
subscripting on USER-INPUT in the case where it contains only
blank spaces.
Use OpenCOBOL 1.1 or greater.
Identification division.
Program-id. 'trimtest'.
*> Compile:
*> cobc -x -free -ffunctions-all TrimTest.cbl
*>
Data division.
Working-Storage Section.
1 myBigStr Pic X(32768) Value Spaces.
Procedure Division.
Display "Enter Something? " With no advancing.
Accept myBigStr.
Display "[" Trim(myBigStr) "]".
Goback.
The trim function also has the options; Leading or Trailing.
cobc -h formore info.
Here's a solution if you work on OpenVMS:
01 WS-STRING-LENGTH PIC S9(04) COMP.
CALL "STR$TRIM" USING BY DESCRIPTOR user_output,
user_input,
BY REFERENCE WS-STRING-LENGTH.
a more general solution:
01 length pic 99.
perform varying length from 1 by 1
until length > 30 or user-input[length] = space
end-perform.
if length > 30
display user-input 'plus some extra text'
else
display user-input[1:length] 'plus some extra text'
end-if.
untested, I don't have a compiler at hand at the moment
There are three ways you can do this.
Use the COBOL functions to determine the string's "length". This is a mix of a couple functions. This is my preferred method, but requires declaring extra variables.
Write your own function to get the "length".
Use knowledge of a "terminating" string. You have to know what key characters indicates an end-of-string, like three spaces or a low-value character.
This example code demonstrates all three.
IDENTIFICATION DIVISION.
PROGRAM-ID. TESTPROG.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ONE-A PIC X(20) VALUE 'RALPH WIGGAM'.
01 ONE-A-TLY PIC 9(02) VALUE ZERO.
01 ONE-A-LEN PIC 9(02) VALUE ZERO.
01 ONE-B PIC X(20) VALUE 'LIKES LEARNDING'.
01 ONE-B-TLY PIC 9(02) VALUE ZERO.
01 ONE-B-LEN PIC 9(02) VALUE ZERO.
01 TWO-A PIC X(20) VALUE 'RALPH WIGGAM'.
01 TWO-A-LEN PIC 9(02) VALUE ZERO.
01 TWO-B PIC X(20) VALUE 'LIKES LEARNDING'.
01 TWO-B-LEN PIC 9(02) VALUE ZERO.
01 THREE-A PIC X(20) VALUE 'RALPH WIGGAM'.
01 THREE-B PIC X(20) VALUE 'LIKES LEARNDING'.
01 THREE-C PIC X(80) VALUE SPACES.
PROCEDURE DIVISION.
DISPLAY ' -- METHOD ONE -- '
INSPECT FUNCTION REVERSE(ONE-A)
TALLYING ONE-A-TLY FOR LEADING SPACES.
SUBTRACT ONE-A-TLY FROM LENGTH OF ONE-A GIVING ONE-A-LEN.
INSPECT FUNCTION REVERSE(ONE-B)
TALLYING ONE-B-TLY FOR LEADING SPACES.
SUBTRACT ONE-B-TLY FROM LENGTH OF ONE-A GIVING ONE-B-LEN.
DISPLAY ONE-A(1:ONE-A-LEN)
' ' ONE-B(1:ONE-B-LEN)
'.'.
DISPLAY ' -- METHOD TWO -- '
PERFORM VARYING TWO-A-LEN FROM LENGTH OF TWO-A BY -1
UNTIL TWO-A-LEN < 1 OR TWO-A(TWO-A-LEN:1) > SPACE
END-PERFORM.
PERFORM VARYING TWO-B-LEN FROM LENGTH OF TWO-B BY -1
UNTIL TWO-B-LEN < 1 OR TWO-B(TWO-B-LEN:1) > SPACE
END-PERFORM.
DISPLAY TWO-A(1:TWO-A-LEN)
' ' TWO-B(1:TWO-B-LEN)
'.'.
DISPLAY ' -- METHOD THREE, NAIVE -- '
* DELIMITING BY JUST ANY SPACES ISN'T GOOD ENOUGH.
STRING THREE-A DELIMITED BY SPACES
' ' DELIMITED BY SIZE
THREE-B DELIMITED BY SPACES
'.' DELIMITED BY SIZE
INTO THREE-C.
DISPLAY THREE-C.
DISPLAY ' -- METHOD THREE, OK -- '
STRING THREE-A DELIMITED BY ' '
' ' DELIMITED BY SIZE
THREE-B DELIMITED BY ' '
'.' DELIMITED BY SIZE
INTO THREE-C.
DISPLAY THREE-C.
EXIT-PROG.
STOP RUN.
and the output looks like this:
-- METHOD ONE --
RALPH WIGGAM LIKES LEARNDING.
-- METHOD TWO --
RALPH WIGGAM LIKES LEARNDING.
-- METHOD THREE, NAIVE --
RALPH LIKES.
-- METHOD THREE, OK --
RALPH WIGGAM LIKES LEARNDING.