How to display an absolute value - cobol

Given the following code:
IDENTIFICATION DIVISION.
PROGRAM-ID. FABS.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 NUM PIC 9 VALUE ZEROS.
01 ABSVAL PIC 99 VALUE ZEROS.
PROCEDURE DIVISION.
PROGRAM-BEGIN.
DISPLAY "This program returns the absolute value of a number.".
DISPLAY SPACE.
DISPLAY "Input value: " WITH NO ADVANCING.
ACCEPT NUM.
IF (NUM = -0) THEN
COMPUTE ABSVAL = 0
ELSE
IF (NUM > 0) THEN
COMPUTE ABSVAL = 0
ELSE
COMPUTE ABSVAL = ABSVAL * -1
END-IF
END-IF.
DISPLAY "|", NUM "| = ", ABSVAL.
PROGRAM-DONE.
STOP RUN.
Why is the output zero? Is there something wrong? And how do you make a signed/negative input?

Thinking of your task, rather than why you get zero, it is easy.
Let's assume you get a signed value with your ACCEPT.
01 value-from-accept PIC S9.
01 absolute-value-for-output PIC 9.
MOVE value-from-accept TO absolute-value-for-output
DISPLAY
"|"
value-from-accept
"| = "
absolute-value-for-output
You may think that something is wrong with the output from value-from-accept (depending on compiler) but you can always MOVE it to a numeric-edited field and DISPLAY that.
Tip: To reverse the sign of a signed field.
SUBTRACT field-to-reverse-sign
FROM ZERO
GIVING the-reversed-field
SUBTRACT is faster than MULTIPLY.
You have defined your field which is ACCEPTed as unsigned.
The first two "legs" of your nested-IF set ABSVAL to zero. The remaining leg takes the existing value of ABSVAL (from the VALUE ZEROS, so it is zero) and multiplies it by minus one. Getting -ve zero (possibly), but then storing it in an unsigned field. So ABSVAL will always be zero when you come to the DISPLAY.
You define a signed field by prefixing the PICture string with an S:
01 a-signed-field PIC S9(5).
Depending on your compiler, you can type a - when entering the data and it'll be held happily as a negative value in a signed field (which you have to define) or you have to code for it yourself.

after your correction above
I am not sure how you are testing it but to just to ensure that the values are stored correct you may want to have both the fields signed i.e. pic S9 or pic S99. Its possible that without the preceding S (sign) the variables are not really storing the negative sign regardless of what the screen is showing.
pls observe what results you get then

Related

COBOL function output as string

123456*
IDENTIFICATION DIVISION.
PROGRAM-ID. "EVEN-OR-ODD".
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Num-1 PIC 9(02).
02 Answer PIC XXXX.
PROCEDURE DIVISION.
GOBACK.
EVEN-OR-ODD.
IF FUNCTION REM(NUM-1, 2) = 0
COMPUTE ANSWER = "Even"
ELSE
COMPUTE ANSWER = "Odd"
END-IF
END PROGRAM EVEN-OR-ODD.
Its a simple even odd function. It should check if number is even return "even" else return "odd"
Can someone explain what's wrong ?
So much things a COBOL compiler would have told you...
GOBACK as first statement, so the rest would not be executed
the program misses a final period and a necessary/reasonable (that depends on the compiler) statement to end the program (END PROGRAM is only parsed for the compilation phase) - you likely want to move your GOBACK. to the end
COMPUTE does not set anything to alphanumeric, you likely want MOVE
there is no way to know what the program would have done, so possibly want DISPLAY instead of MOVE
NUM-1 is never set and has no initial VALUE - so it could theoretically even abend

assumed decimal as input - tab and enter add trailing zeros

Good evening,
I just started learning Cobol, and to practice, I wanted to program a simple multiplication program, working with two decimal numbers given by the user.
So I wrote the following
IDENTIFICATION DIVISION.
PROGRAM-ID. exo.
DATA DIVISION.
WORKING-STORAGE SECTION.
77 a PIC 9(2)V9.
77 b PIC 9(2)V9.
77 result PIC 9(4)V99.
screen section.
1 pla-title.
2 blank screen.
2 line 1 col 1 value 'Multiplication'.
1 pls-numbers.
2 line 4 col 2 value 'Number 1 : '.
2 PIC 9(2)V9 to a required.
2 line 5 col 2 value 'Number 2 : '.
2 PIC 9(2)V9 to b required.
1 pla-result.
2 line 7 col 2 PIC 9(2)V9 from a.
2 col 7 value 'x'.
2 col 9 PIC 9(2)V9 from b.
2 col 13 value '='.
2 col 15 PIC 9(4)V99 from result.
PROCEDURE DIVISION.
display pla-title.
accept pls-numbers.
compute result = a * b.
display pla-result.
END PROGRAM exo.
The issue here is not the multiplication part, which works perfectly. The problem is the input. Every time I press tab or enter, there is a 0 added at the end. For instance, typing 9,9,9,tab,9,9,9,enter multiplies 900 with 990, since the format only takes the last three digits of 99900 (tab+enter) and 9990 (enter).
I tried the same program with integers, it works perfectly. I tried the same with real decimals too (9(2).9), and the input works, but I have a problem with the multiplication (not a numeric value), that I will try to understand later, one problem at the time.
So in short, the question is to know why the input is modified by typing tab and enter, that in my understanding is used to navigate the accept fields.
Thank you very much for your help!
How the input is automatically adjusted on field change/finish of the accept depends on the compiler/runtime actually in use (it is good in most times to add this information in the question), but most COBOL variants want a "." (or in the case of DECIMAL-POINT IS COMMA a ",") entered to get the decimal part correct.
Actually the results with an implied decimal-point and ACCEPT may not be what you want it to do. I suggest to try using a numeric-edited field like ZZ9.99 (which is auto-de-edited on MOVE to a field you do the calculation with [if the stored data matches the editing symbols] after the ACCEPT) or a plain PIC X and a MOVE FUNCTION NUMVAL (input-field) TO a afterwards (this should work on any compiler including this function).

COBOL Beer on the Wall Program

I'm making the "99 Bottles" program, but with user input on how many to take down. I'm very new to COBOL and I'm definitely overlooking something simple or just completely thinking about this the wrong way.
The following is what I currently have:
IDENTIFICATION DIVISION.
PROGRAM-ID. HW.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COUNTER PIC S99.
01 BOTTLES PIC Z9.
01 BOTTLES-REMAINING PIC Z9.
01 NUM PIC s9(02) VALUE 0.
PROCEDURE DIVISION.
PERFORM VARYING COUNTER FROM 99 BY NUM UNTIL COUNTER = 0
DISPLAY "How many bottles would you like to take down?"
ACCEPT NUM
MOVE COUNTER to Bottles
subtract NUM FROM COUNTER GIVING BOTTLES-REMAINING
DISPLAY SPACES
EVALUATE COUNTER
WHEN 1
DISPLAY " 1 bottle of beer on the wall, "
" 1 bottle of beer."
DISPLAY "Take one down and pass it around, "
"no more bottles of beer on the wall."
WHEN 2 Thru 99
DISPLAY BOTTLES " bottles of beer on the wall, "
BOTTLES " bottles of beer."
DISPLAY "Take one down and pass it around, "
BOTTLES-REMAINING
" bottles of beer on the wall."
END-EVALUATE
END-PERFORM
GOBACK.
I need to make the NUM clause negative in the following statement (or the data division) so it will subtract from the counter:
PERFORM VARYING COUNTER FROM 99 BY NUM UNTIL COUNTER = 0
I see a few issues here.
First, and this is from admittedly faded memory, but I seem to recall that the VARYING clause required a constant value for the delta. I don't think you can use an actual changing NUM to do this.
So your loop would be better off not using the VARYING clause and instead be something like (code here may not be syntactically correct COBOL, it's meant more to show intent and/or method):
set counter to 99
perform until counter = 0
blah blah blah then change counter
end perform
Second, your little ditty doesn't make sense any more if you're allowed to remove more than one bottle at a time. The statements for the third stanza of the rhyme should be modified similarly to the bottles-left stanza:
evaluate num
when 1
display "Take one down and pass it around, "
when 2 thru 99
display "Take ", num, " down and pass them around, "
end evaluate
And, finally, you probably want to avoid the situation where you remove more bottles than you have available (or less than one, for that matter). That can be done by silently enforcing those limits (clamping) immediately after getting the user input:
accept num
if num is less than one
set num to one
end if
if num is greater than counter
set num to counter
end if
You could also complain and require the user to enter a valid quantity but the easiest solution is probably just to clamp it.

Data type in COBOL

I have written the following program, I am confused why when I compile the program I get an error saying that A-COL(1,1) is not a numeric value while displaying A-COL(1,1) gives me 1.
IDENTIFICATION DIVISION.
PROGRAM-ID. TEST1.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 DIFF PIC 9(3).
01 ARRAY.
05 A-ROW OCCURS 99 TIMES.
10 A-COL OCCURS 2 TIMES.
15 TABLE-CONTENT PIC 9(3).
PROCEDURE DIVISION.
MOVE 1 TO A-COL(1,1).
MOVE 2 TO A-COL(2,1).
DISPLAY A-COL(1,1).
COMPUTE DIFF = A-COL(1,1) - A-COL(2,1).
DISPLAY DIFF.
STOP RUN.
Change the A-COL definition to
"10 A-COL PIC 9(3) OCCURS 2 TIMES."
and remove the TABLE-CONTENT.
Group variables are considered alphanumeric (X type) so cannot be used in a computation.
Alternatively you may do this - refer to the address location using the actual numeric field.
PROCEDURE DIVISION.
MOVE 1 TO TABLE-CONTENT(1,1).
MOVE 2 TO TABLE-CONTENT(2,1).
DISPLAY A-COL(1,1).
COMPUTE DIFF = TABLE-CONTENT(1,1) - TABLE-CONTENT(2,1).
DISPLAY DIFF.
Also you might want to make DIFF signed.
Additional Information
A-COL(1,1) displays "1" because it stores the data as "1xx" where x = space. That is not a numeric value. When you run the solutions here you will notice that display line produces "001".
Keep your WORKING-STORAGE structure the same. However, your data-elements are not A-COL, but THE-CONTENT. So use THE-CONTENT, not A-COL.
IDENTIFICATION DIVISION.
PROGRAM-ID. TEST1.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 DIFF PIC S9(3).
01 ARRAY.
05 A-ROW
OCCURS 99 TIMES.
10 A-COL
OCCURS 2 TIMES.
15 TABLE-CONTENT PIC 9(3).
PROCEDURE DIVISION.
MOVE 1 TO TABLE-CONTENT ( 1 1 )
MOVE 2 TO TABLE-CONTENT ( 2 1 )
DISPLAY
">"
TABLE-CONTENT ( 1 1 )
"<"
COMPUTE DIFF = TABLE-CONTENT ( 1 1 )
- TABLE-CONTENT ( 2 1 )
DISPLAY
">"
DIFF
"<"
STOP RUN
.
Your structure is better, because it is easier to maintain. If you ever want to REDEFINES TABLE-CONTENT, you can, without changing the structure. Not so if you "complicate" the structure now.
Yes, if you MOVE a numeric literal to a group-item, an alpha-numeric MOVE is carried out, the result will be your literal left-justified and space-padded to the right, or truncated to the right, or just fitting, depending on the size of your literal.
Although conceptually you have "columns" in your table (COBOL doesn't have arrays, it has tables with OCCURS), be aware that you cannot access a column as a whole. In storage you have row-1-col-1, row-1-col-2, row-2-col-1, row-2-col-2 through to row-99-col-1, row-99-col-2.
Any arithmetic (ADD, SUBTRACT, MULTIPLY, DIVIDE and COMPUTE) can only use numeric fields or literals as source-data. It is not enough that a field contains "a number", it must be a numeric field.
The GIVING (of ADD, SUBTRACT, MULTIPLY and DIVIDE) can place the result in a non-numeric field of a particular type, a numeric-edited field. This is a field with a PICture clause containing numeric-editing PICture symbols.

Cobol storing file to table

I'm trying to store a pattern received from text file into a table in COBOL.
I am using READ.. INTO.. statement to do so, and here is what I have so far.
WORKING-STORAGE SECTION.
01 ROWCOL.
03 NROW PIC 9(3).
03 NCOL PIC 9(2).
01 PATT-INIT.
03 ROW PIC X OCCURS 1 TO 80 TIMES
DEPENDING ON NCOL.
01 PATT.
03 COL OCCURS 1 TO 80 TIMES
DEPENDING ON NCOL.
05 ROW OCCURS 1 TO 100 TIMES
DEPENDING ON NROW PIC X.
PROCEDURE DIVISION.
MAIN-PARAGRAPH.
OPEN INPUT INPUT-FILE.
READ INPUT-FILE INTO ROWCOL.
PERFORM READ-PATTERN
STOP RUN.
READ-PATTERN.
READ INPUT-FILE INTO PATT-INIT(1:NCOL).
The pattern in the input.txt would look something like this:
011000
001010
010100
The thing about this is that, I'm not sure how to place the PATT-INIT array into the PATT 2d-array. I'm only using the PATT-INIT array to receive row-by-row the pattern in each line. Then, I'm trying to store it into PATT 2d array such that I can access each number by the index numbers. e.g. PATT(1:2) would return 1.
Please give me some pointers on how to implement this. If READ.. INTO.. is not the way to go, I'm more than happy to receive other suggestions.
I think part of your problem is that you think things like (1:NCOL) are doing one thing, when in fact they mean something completely different. The notation indicate "reference modification". You probably are expecting ordinary subscripting, or at least "reference modification" from a variable starting point with a fixed length of one.
01 a-nicely-name-table.
05 FILLER OCCURS 80 TIMES.
10 a-nicely-named-row-entry.
15 FILLER OCCURS 6 TIMES.
20 a-nicely-named-column-entry PIC X.
The data from your READ goes into a-nicely-name-row-entry ( subscripted ). Once everything is there, you can reference a paricular column on a particula row by a-nicely-named-column-entry ( a-row-subcript, a-column-subscript ).
Note, without the ":" this is subscripting, not "reference modification". The comma is optional.
You need to ensure that you don't go "outside" the bounds of the number of rows you put in the table, and also that you do not "overflow" the table with input data.
You can use indexes for subscripting (INDEXED BY on the OCCURS definition). I haven't in the example, as it is unclear what you are trying to achieve.
If I am understanding your question properly, there may be a couple of problems. Bill an Bruce have noted
that you seem to be mixing up subscript and reference modification. Basically
something like:
DISPLAY PATT-INT (1:3)
will display the first 3 characters of PATT-INT. This is a reference modification. While
DISPLAY ROW OF PATT (1, 3)
will display the character at COL 1, ROW 3 of the PATT table. Notice that you need to reference the "lowest" level element name here so maybe renaming some of your data structures make it a little easier to "follow".
The other problem might be a confusion between rows and columns...
The input-txt file you gave has 3 lines of data (rows). Each line has 6 characters (columns). Your
declaration of PATT-INIT seems to re-enforce that since it has an OCCURS NCOL times. When you read one
line of data you get 6 columns for that row. However, the PATT
table flips this on its side. It is declared with a Column then Row layout.
This layout means you cannot read directly into it from input.txt because the table declaration
does not follow the file layout.
Two solutions to that problem.
This is the one I think you might have been trying to work toward:
Read each input.txt line and store it in PATT such that it
becomes 6 columns in PATT for the same row. For example the first row of input: 011000 would be
stored in PATT (1, 1) through PATT (6, 1), 6 columns, 1 row. Note: You
indicated that ROW OF PATT (1, 2) should have a value of '1' - here ROW OF PATT (2, 1) would be '1'.
That aside, you could read one line of input into a single dimension array (PATT-INIT) and then
redistribute it into
the PATT table. Here is a program outline:
MAIN-PARAGRAPH.
OPEN INPUT INPUT-FILE
READ INPUT-FILE INTO ROWCOL
PERFORM VARYING WS-R FROM 1 BY 1
UNTIL WS-R > NROW
PERFORM READ-1-ROW
END-PERFORM
CLOSE INPUT-FILE
.
READ-1-ROW.
READ INPUT-FILE INTO PATT-INIT (1:NCOL)
PERFORM VARYING WS-C FROM 1 BY 1
UNTIL WS-C > NCOL
MOVE ROW OF PATT-INIT (WS-C) TO ROW OF PATT (WS-C, WS-R)
END-PERFORM
.
The other solution might to be redefine PATT as
01 PATT.
03 ROW OCCURS 1 TO 100 TIMES
DEPENDING ON NROW.
05 COL OCCURS 1 TO 80 TIMES
DEPENDING ON NCOL PIC X.
Now you can simply read as follows:
MAIN-PARAGRAPH.
OPEN INPUT INPUT-FILE
READ INPUT-FILE INTO ROWCOL
PERFORM VARYING WS-R FROM 1 BY 1
UNTIL WS-R > NROW
READ INPUT-FILE INTO ROW (WS-R) (1:NCOL)
END-PERFORM
CLOSE INPUT-FILE
You can drop the PATT-INIT working storage since it is no longer referenced.
Note: With this layout COL OF PATT (1, 2) = '1'
Flesh out the above with proper data edits, bounds checks and FILE-STATUS checking after each I/O to
complete the program.
The problem is not the read into it is with PATT-INIT(1:NCOL). This is called
Reference Modification.
Cobol does Line or record orientated IO. so
READ INPUT-FILE INTO PATT-INIT
is probably what you want. To access an array element use (i,j) not (i:j)

Resources