Declaring variables in COBOL - variables

I'm sorry if this question has been already answered, I've tried to search all over this site and I couldn't find anything.
I created a calculator that receives value and option from Mainframe Replies and then does the arithmetic operations.
My main problem is that if I declare a pic 9(3) and the value is 2 it'll display this way:
200 instead of 2.
How could I format this in order to avoid this problem?
Thank you!

For several reasons, I suggest something along these lines rather than what has already been suggested: your input field is short, so no real problem with dealing with individual names for three fields; you need to validate the input before calculating; it'll give you some practice with COBOL field definitions; it is the way I'd do it for this case (short, simple-format, data, requiring validation).
The procedure code is simple, and can be structured in any number of ways.
Your data may be: 4+ characters (invalid), zero characters (invalid), three characters, two characters, one character, and must be numeric (you haven't mentioned it is a Hex Calculator) for these last three, otherwise invalid.
Make the procedure code reflect that.
To keep things simple, deal with the major invalid data first (too long, too short) and don't let that near the rest of the processing.
With those out of the way, it is easy to identify input of one character (two trailing spaces) then two characters (now the only remaining possibility when space in third position) then what is left must be three characters.
Having given each field an individual name, they can be tested for NUMERIC in their own piece of code (I like to de-clutter IF/EVALUATE by using PERFORM, but many don't) and simply MOVEd to a PIC 999/9(3) field if valid.
The PIC 999/9(3) field can be defined as COMP-3/PACKED-DECIMAL. An alpha-numeric (PIC X...) field can be moved directly to that. The reason you may want to do this is because we know for sure it is going in to a calculation, which means the compiler will have to convert it to packed-decimal anyway, so you can consider the conversion up-front. If all other fields in your calculation are binary, you could subsequent to the first MOVE, do a second move to a COMP/COMP-4/BINARY/COMP-5 field (you cannot directly MOVE a PIC X... to a binary field).
01 INPUT-LINE.
05 INPUT-VALUE.
88 IV-NO-VALUE VALUE SPACE.
10 IV-THREE-DIGITS.
15 IV-TWO-DIGITS.
20 IV-ONE-DIGIT PIC X.
20 FILLER PIC X.
15 FILLER PIC X.
88 IV-ONE-TRAILING-BLANK
VALUE SPACE.
05 FILLER REDEFINES INPUT-VALUE.
10 FILLER PIC X.
10 FILLER PIC XX.
88 IV-TWO-TRAILING-BLANKS
VALUE SPACE.
05 FILLER PIC X(77).
88 IV-NO-EXTRA-DATA VALUE SPACE.
01 INPUT-VALUE-FOR-CALCULATION PIC 9(3).
PERFORM VALIDATE-INPUT
VALIDATE-INPUT.
IF IV-NO-EXTRA-DATA
EVALUATE TRUE
WHEN IV-NO-VALUE
set some unique error
WHEN IV-TWO-TRAILING-BLANKS
PERFORM ONE-INPUT-CHARACTER
WHEN IV-ONE-TRAILING-BLANK
PERFORM TWO-INPUT-CHARACTERS
WHEN OTHER
PERFORM THREE-INPUT-CHARACTERS
END-EVALUATE
ELSE
set some unique error
END-IF
ONE-INPUT-CHARACTER.
IF IV-ONE-DIGIT NUMERIC
MOVE IV-ONE-DIGITS TO INPUT-VALUE-FOR-CALCULATION
ELSE
set some unique error
END-IF
TWO-INPUT-CHARACTERS.
IF IV-TWO-DIGITS NUMERIC
MOVE IV-TWO-DIGITS TO INPUT-VALUE-FOR-CALCULATION
ELSE
set some unique error
END-IF
THREE-INPUT-CHARACTERS.
IF IV-THREE-DIGITS NUMERIC
MOVE IV-THREE-DIGITS TO INPUT-VALUE-FOR-CALCULATION
ELSE
set some unique error
END-IF
You're a beginner, so you haven't wondered exactly why you ended up with 200.
ACCEPT, on the Mainframe, does not do numeric alignment, because ACCEPT is actually taking all the data that is available, slapping it into your field, and truncating any excess.
So that will get you 2 (that is two trailing blanks). Your field is PIC 999/9(3), so it is unsigned. Because it is unsigned the compiler will ensure that it is so when it is used as the source of a VERB. This will give you 2 0, because the left-hand part of the third byte (on the Mainframe) will be set to F from 4. X'40' is a space, which it was originally. X'F0' is zero, which is what you get when the 4 is changed to an F.
You still have that space in the middle. However, by the time you use that field for a calculation, all the left-parts of each byte (except the sign in the final one) will be stripped out to "pack" the field, and to put a result back in a PIC 999/9(3) Fs will simply be inserted as part of the "unpack". Lo, your two followed by two blanks is now 200!

Related

RAND() not consistently generating the right length value

I've got the following code in place with the idea being that I need a 30 character random number generated each time the stored procedure is called and the odd thing is that in most cases it works as intended but in other seemingly random cases it will only generate a 28 character random number.
'\\xxx-servername\folder\'+
CAST(CAST((RAND()*1000000000000000000000000000000) as decimal(30))as varchar(30)) +
RAM.AccountNumber+HRMRN.PrefixMedicalRecordNumber+'ESTIMATE N00001'+
REPLACE(CONVERT(VARCHAR(12),ISNULL(HRM.Birthdate,HRM.BirthdateComputed),111),'/','')+HRM.Sex+
REPLACE(CONVERT(VARCHAR(12),GetDate(),111),'/','')+LEFT(REPLACE(CONVERT(VARCHAR(12),GetDate(),108),':',''),4)+'.PDF' as [CPFileName]
Hope maybe someone can offer some advice because I'm at a loss...
I suspect that your system is automatically removing leading zeros. You can either re-insert those zeros yourself, or else construct your number using something like:
number <- ""
number.append(randomDigit(1,9))
repeat 29 times
number.append(randomDigit(0,9))
end repeat
That guarantees that you do not get a leading zero.

Is format ####0.000000 different to 0.000000?

I am working on some legacy code at the moment and have come across the following:
FooString = String.Format("{0:####0.000000}", FooDouble)
My question is, is the format string here, ####0.000000 any different from simply 0.000000?
I'm trying to generalize the return type of the function that sets FooDouble and so checking to make sure I don't break existing functionality hence trying to work out what the # add to it here.
I've run a couple tests in a toy program and couldn't see how the result was any different but maybe there's something I'm missing?
From MSDN
The "#" custom format specifier serves as a digit-placeholder symbol.
If the value that is being formatted has a digit in the position where
the "#" symbol appears in the format string, that digit is copied to
the result string. Otherwise, nothing is stored in that position in
the result string.
Note that this specifier never displays a zero that
is not a significant digit, even if zero is the only digit in the
string. It will display zero only if it is a significant digit in the
number that is being displayed.
Because you use one 0 before decimal separator 0.0 - both formats should return same result.

FORTRAN77 How to throw error for the following: division symbol, timeout, very big floating value:

1 for certain symbols like (/), (,) and (;) while taking input.
2. Timeout error while taking input
3. very big floating value as input
4. and for improper inputs like - 4/3
I found out how to time-out the program after a specific time:
https://gcc.gnu.org/onlinedocs/gcc-4.3.2/gfortran.pdf (find: alarm)
If I interpret your question correctly, you want to check user input for correct values and interpret lists and fractions. I'm assuming you mean from console, a la
read(*,*) character-variable
The other option is to use formatted input, for example
read(*,'(i4)') integer-variable
which would read an integer with four digits.
This method would possibly already remove some of your problems, because the user input has to match the specified format or the program reports a runtime error. It is possible to specify the number of input values as well (separated by whitespace, ',' or ';'). Hence if you know beforehand how many values you are getting, the user can enter lists. If you make the requirements clearer, it will be easier to help. Fortran is a bit finicky for I/O.
If you really need the input to be of a general not-defined-at-compile-time type, you'll have to parse the string. This is also true if you want the user to be able to enter fractions like '4/3'.
I'm not aware of a method to restrict the time which a user has to enter values. It may be possible, but I've never seen it.
For too big or improper values you just can, for example, wrap the read statement in an endless do loop and exit if the number(s) is/are correct
do
read(*,'(i6)') x
if ( (x.lt.1e5).and.(x.ge.0) ) exit
end do
This would request an integer x from the user until the input is smaller than 100 000 and at least 0.
edit after discussion in comments:
The following code may be what you want:
implicit none
integer :: x
character(len=10) :: y
y=''
print*,'Enter one integer:'
do
read(*,'(i10,a)') x,y
if( (y.eq.'').and.(x.lt.1e5) ) exit
print*,'Enter one valid integer, smaller than 100 000, only:'
end do
print*,x
end
It just reads until there is exactly one integer smaller than 100 000 in the input. If you want a better user experience you can catch 'very' invalid input (that the program complains about and stops) with the iostat parameter.
One thing though: on my two available compilers (GCC 4.4.7 and Intel fortran compiler 11.0) the forward slash '/' is not a valid integer input and the program stops. If that is different for your compiler the code above should still work, but I can't test that.

Cobol Reading Record with a Table

I'm trying to display some data that I'm reading into a table. However, I keep getting the error:
IN-FUND-NBR was not a uniquely defined name...Expected a reference-modification specification but found ")".
***EDIT: Okay, so I found the root of the problem. However, can't I still access IN-FUND-NBR as it sits? I tried the following, but it does not work:
DISPLAY "IN-FUND-NBR = " IN-FUND-NBR (MF-SALE-SUB) OF IN-MF-SALE
***END EDIT
I have the following record defined as follows:
01 SALES-RECORD.
05 IN-CITY-NAME PIC X(20).
05 IN-CUSTOMER-NAME PIC X(20).
05 IN-MF-SALE OCCURS 4.
10 IN-FUND-NBR PIC 9(2).
10 IN-PRICE-FLAG PIC 9.
10 IN-PURCH-AMT PIC 9(5)V99.
I'm trying to extract the first instance of IN-FUND-NBR by doing the following in a paragrah:
PERFORM
VARYING MF-SALE-SUB FROM 1 BY 1
UNTIL MF-SALE-SUB > 4
DISPLAY "Fund Number: " IN-FUND-NBR(MF-SALE-SUB)
END-PERFORM.
In your program you have IN-FUND-NBR defined more than once. The other definition(s) may be in a copybook, or something you have coded yourself without realising. The compiler discards the reference to the field.
The second diagnostic message about the reference-modification is because having discarded the reference to your data-name the compiler then encounters the opening parenthesis and your subscript. This message will disappear when you correct the problem.
Either, ensure that the data-names are unique. Or, in the nutty situation that this is not possible, you have to use qualification. You do this by using IN or OF and referencing a higher level data-name.
From what you have shown:
DISPLAY "Fund Number: " IN-FUND-NBR OF SALES-RECORD (MF-SALE-SUB)
should work.
Although you can use qualificationto get around the problem, many are like me and find it a complete waste of time and patience, and others, especially beginners, find it a source of confusion. Try your best to always have unique data-names.

How to increase the length of select-options in UI

As I understood, select-options in abap just takes 45 characters from UI.
Whatever I assign the type of select-option, it doesnt take more then 45 characters.
SELECT-OPTIONS: s_key FOR somlreci1-receiver NO INTERVALS VISIBLE LENGTH 100.
somlreci1-receiver is char(1215). But I cannot write more than 45 into that select-option.
Any way to increase this length ?
This official link
http://help.sap.com/abapdocu_70/en/ABAPSELECT-OPTIONS.htm
says it isn't possible to pass input larger than 45 chars, sorry :|
At the end of the documentation posted by #vlad-ardelean it mentions that:
If a selection criterion for data types is supplied with data when
calling up an executable program with SUBMIT
...
If the selection criterion is declared with the addition NO-DISPLAY,
no conversion routine or truncation will be performed for the first
row either.
You could declare the select-options as NO-DISPLAY in your main program, then call it from a second program with
SUBMIT programname WITH so_field EQ lv_longdata SIGN 'I'.
...or similar to pass the long value to the main program. It's a pretty convoluted way of doing it, however.
In addition to #vlad-ardelean's answer: It might be interesting to note that in recent releases, the maximum field length was raised to 255 characters (see http://help.sap.com/abapdocu_731/en/ABAPSELECT-OPTIONS.htm).