Infinite loop in cobol program - infinite-loop

I am new to old COBOL. I am trying an example on online compiler. But, the code I am using is entering an infinite loop. The code is :
IDENTIFICATION DIVISION.
PROGRAM-ID. Conditions.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Char PIC X.
88 Vowel VALUE "a", "e", "i", "o", "u".
88 Consonant VALUE "b", "c", "d", "f", "g", "h"
"j" THRU "n", "p" THRU "t", "v" THRU "z".
88 Digit VALUE "0" THRU "9".
88 ValidCharacter VALUE "a" THRU "z", "0" THRU "9".
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter lower case character or digit. No data ends.".
ACCEPT Char.
PERFORM UNTIL NOT ValidCharacter
EVALUATE TRUE
WHEN Vowel DISPLAY "The letter " Char " is a vowel."
WHEN Consonant DISPLAY "The letter " Char " is a consonant."
WHEN Digit DISPLAY Char " is a digit."
WHEN OTHER DISPLAY "problems found"
END-EVALUATE
END-PERFORM.
STOP RUN.
What I understand (only a rough idea) is that PERFORM UNTIL is like while, EVALUATE is like SWITCH and WHEN is like CASE in C. So, shouldn't the loop break on entering a valid character?

You do not change anything within the loop. The only code you have within the loop is an EVALUATE (changes no data) and four DISPLAY statements (changes no data).
Looping whilst changing nothing is an infinite loop.
You need to include a second ACCEPT statement after the END-EVALUATE.
If you had coded the equivalent in C, you'd have got an infinite loop as well.

As Bill Woodger said, you didn't change the value of char, so it will keep looping forever.
Moreso, if you correct that issue, the program will still not work properly: you have some strange logic on it:
It will PERFORM while Char has a valid character on it.
But it will escape the EVALUATE if the character is not a Vowel, Consonant or Digit.
My best guess is this is how you attempt it to work:
IDENTIFICATION DIVISION.
PROGRAM-ID. Conditions.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Char PIC X.
88 Vowel VALUE "a", "e", "i", "o", "u".
88 Consonant VALUE "b", "c", "d", "f", "g", "h"
"j" THRU "n", "p" THRU "t", "v" THRU "z".
88 Digit VALUE "0" THRU "9".
88 ValidCharacter VALUE "a" THRU "z", "0" THRU "9".
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter lower case character or digit. No data ends.".
MOVE "a" to Char
PERFORM UNTIL NOT ValidCharacter
ACCEPT Char
EVALUATE TRUE
WHEN Vowel DISPLAY "The letter " Char " is a vowel."
WHEN Consonant DISPLAY "The letter " Char " is a consonant."
WHEN Digit DISPLAY Char " is a digit."
END-EVALUATE
END-PERFORM.
DISPLAY "Non-valid character!"
STOP RUN.
Changes:
I put the ACCEPT inside the PERFORM.
Because that, and the way it was declared, Char now has an invalid character (empty space). So i move a valid character ("a") to validate the perform criteria with MOVE "a" to Char.
I got rid of the WHEN OTHER line, because if it really is OTHER, it means it is not a Vowel, Consonant or Digit, and that's exactly what the PERFORM is doing: waiting until there's an invalid character in Char.
My output:
Enter lower case character or digit. No data ends.
d
The letter d is a consonant.
e
The letter e is a vowel.
q
The letter q is a consonant.
a
The letter a is a vowel.
1
1 is a digit.
#
Non valid character!
COBOL STOP RUN at line 218 in program TEST.CBL

Related

How does the digits parameter in R's prettyNum() function work?

In R I'm using the prettyNum() function to format some numbers but I'm having a hard time getting the number of digits I want. The help docs say:
the desired number of digits after the decimal point (format = "f") or significant digits (format = "g", = "e" or = "fg").
Default: 2 for integer, 4 for real numbers. If less than 0, the C default of 6 digits is used. If specified as more than 50, 50 will be used with a warning unless format = "f" where it is limited to typically 324. (Not more than 15–21 digits need be accurate, depending on the OS and compiler used. This limit is just a precaution against segfaults in the underlying C runtime.)
To me, this seems to mean that prettyNum(404.5142, digits = 2) should give me "404.51" but in reality it produces "405". Can someone explain how to get it to round to a fixed number (say 2) of digits after the decimal place? I'd like it to include tailing 0s too.
The help file for prettyNum is also documenting formatC, to which the parameter digits belongs. The prettyNum function does not have a parameter called digits.
The reason why this doesn't result in an error is that your argument digits is being passed via ... to format.
...       arguments passed to format.
In format, the parameter digits is different to the digits parameter in formatC. It means the number of significant digits, not the number of digits after the decimal point. Yes, this is a bit confusing in the documents, but it means for example that you could do:
prettyNum(404.5142, digits = 5)
#> [1] "404.51"
However, this will give you the wrong number of digits if you do, for example:
prettyNum(44.5142, digits = 5)
#> [1] "44.514"
And therefore you would be safer to use something like formatC, which allows
formatC(404.5142, format = "f", digits = 2)
#> [1] "404.51"
and
formatC(44.5142, format = "f", digits = 2)
#> 1] "44.51"
Which seems to be what you are looking for.

R Remove specific character with range of possible positions within string

I would like to remove the character 'V' (always the last one in the strings) from the following vector containing a large number of strings. They look similar to the following example:
str <- c("VDM 000 V2.1.1",
"ABVC 001 V10.15.0",
"ASDV 123 V1.20.0")
I know that it is always the last 'V', I would like to remove.
I also know that this character is either the sixth, seventh or eighth last character within these strings.
I was not really able to come up with a nice solution. I know that I have to use sub or gsub but I can only remove all V's rather than only the last one.
Has anyone got an idea?
Thank you!
This regex pattern is written to match a "V" that is then followed by 5 to 7 other non-"V" characters. The "[...]" construct is a "character-class" and within such constructs a leading "^" causes negation. The "{...} consturct allows two digits specifying minimum and maximum lengths, and the "$" matches the length-0 end-of-string which I think was desired when you wrote "sixth, seventh or eighth last character":
sub("(V)(.{5,7})$", "\\2", str)
[1] "VDM 000 2.1.1" "ABVC 001 10.15.0" "ASDV 123 1.20.0"
Since you only wanted a single substitution I used sub instead of gsub.
You can use:
gsub("V(\\d+.\\d+.\\d+)$","\\1",str)
##[1] "VDM 000 2.1.1" "ABVC 001 10.15.0" "ASDV 123 1.20.0"
The regex V(\\d+.\\d+.\\d+)$ matches the "version" consisting of the character "V" followed by three sets of digits (i.e., \\d+) separated by two "." at the end of the string (i.e., $). The parenthesis around the \\d+.\\d+.\\d+ provides a group within the match that can be referenced by \\1. Therefore, gsub will replace the whole match with the group, thereby removing that "V".
Since you know it's the last V you want to remove from the string, try this regex V(?=[^V]*$):
gsub("V(?=[^V]*$)", "", str, perl = TRUE)
# [1] "VDM 000 2.1.1" "ABVC 001 10.15.0" "ASDV 123 1.20.0"
The regex matches V before pattern [^V]*$ which consists of non V characters from the end of the String, which guarantees that the matched V is the last V in the string.

round() not displaying digits

When I read in data that has a few digits after the decimal place, I notice that R doesn't give me the full value when I ask for it, even when I use round(). Any ideas what could be going on? Here are some example data:
test <- data.frame("A"=c("A", "B", "C", "D"), "B"=c(0.254, 0.457, 0.123, 1.089), "C"=c(101.1, 101.2, 354.1234, 354.1235))
When I enter:
test[1,2]
the output is 0.254. But when I try to see the same thing from the 3rd column, where I have numbers with digits in the hundreds place out to the millionths place (i.e. XXX.XXXX), the output doesn't give me any numbers after the decimal place. For example, when I enter:
test[3,3]
the output is 354.
When I try:
round(test[3,3], digits=4)
I still get 354. But when I subtract like this:
test[3,3]-test[4,3]
the output is 0.0001. What is going on here and how can I see 4 digits after the decimal when I ask for them?

skipping recursion

The first line is a number, int x. The following m lines contain letters. After m lines, you read in a number, int y.
The goal is to find the soluiton number, int y, from recursion of 1 letter from each line.
The problem states that there’s a much faster solution which avoids going through each possible password. That is where my question is. How can this be done? Any help would be greatly appreciated.
This is not that complicated. You can count the number of letters in the m lines. Then you calculate a value for every line of letters, that specifies how many possible solutions are skipped, if one letter in the referenced line is skipped. Visualized:
abc -> 3 letters
xy -> 2 letters
dmnr -> 4 letters
if you skip from the n-th letter to the n+1-th letter in the "abc" line, you skip as many possible solutions as the product of the length of every following line says. so you skip 2*4 solutions -> 8 solutions.
repeat this step for xy -> 4 solutions skipped.
the last line skips alwasy 1 solution, because it is the recursion path itself.
so now you know, how many solutions you skip, if you skip to some specific letter. the last thing is simple. you start with 1 and add the calculated value of each line to the number, until it reaches exactly r.
means in c++:
int v = 1, r=10;
int i1=0, i2=0, i3=0;
while (v<=r-8) {
i1++;
v+=8;
}
while (v<=r-4) {
i2++;
v+=4;
}
while (v<=r-1) {
i3++;
v++;
}
now i1 is the index of the letter you need to use from the "abc" line, i2 is the index of the letter from "xy" and i3 from "dmnr" :) thats all. the algorithm should end with i1=1, i2=0, i3=1 -> "b" + "x" + "m"
I hope this helps. It removes the recursion, but that's no problem, is it? ;)

converting numerical values into decimal numbers

I have text file with values with one or two or some with 3 decimal points.These values are generated by the software based on the signal intensity of genes.When I tried to compute the distance matrix out of it,I got the warning message:
Warning message:
In dist(sam) : NAs introduced by coercion
A sample text file is given below:
sample1
a 23.45.12
b 123.345.234
c 45.2311.34
I need to convert these values either with one decimal point or as real numbers so that i can compute distance matrix out of it from which i can use it for clustering.My expected result is given as follows:
sample1
a 23.45
b 123.345
c 45.2311
Pleaso do help me
You can do this in one line of code with as.numeric and gsub with a suitable regular expression:
sample1 <- c(
a = "23.45.12",
b = "123.345.234",
c = "45.2311.34"
)
as.numeric(
gsub("(\\d+\\.\\d+)\\..*", "\\1", sample1)
)
[1] 23.4500 123.3450 45.2311
The regular expression:
\\d* finds one or more digits
\\. finds a period
Thus (\\d+\\.\\d+) finds two sets of digits with a period inbetween, and then groups it (with the brackets)
Finally, \\..* finds a period followed by a complete wildcard
Then gsub replaces the entire string with only what was found inside the brackets. This is called a regular expression back reference, indicated by \\1.

Resources