I'm working on a Java CPU benchmark that tests the number of recursive calls for a method that returns the sum of all prime numbers, from a variable called start. This is how my method looks like:
private long recursive(long start, int size, int counter) {
long temp = findNextPrime(start);
if (temp > size) return 0;
try {
return temp + recursive(temp, size, counter + 1);
} catch (StackOverflowError e) {
System.out.println("Reached nr " + start + "/" + size + " after " + counter + " calls.");
return 0;
}
}
I am looking for a StackOverflowError exception and want to output the last sum calculated before reaching that exception. Everything seems to work fine from a logical point of view, when I'm using a smaller value for size. The prime numbers are picked up correctly, and the sum is calculated correctly.
The problem is for greater values of size, where the exception is actually thrown. When I don't output anything in the catch() section (I comment the System.out.println() line), everything seems to be okay, but when I just let the print line as it is, I receive the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class java.lang.invoke.StringConcatFactory
at java.base/java.lang.invoke.DirectMethodHandle.shouldBeInitialized(DirectMethodHandle.java:347)
at java.base/java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:193)
at java.base/java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:210)
at java.base/java.lang.invoke.DirectMethodHandle.make(DirectMethodHandle.java:105)
at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:2322)
at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:2278)
at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:2520)
at java.base/java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:2466)
at java.base/java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:592)
at benchmark.cpu.CPURecursionLoopUnrollingBenchmark.recursive(CPURecursionLoopUnrollingBenchmark.java:61)
at benchmark.cpu.CPURecursionLoopUnrollingBenchmark.recursive(CPURecursionLoopUnrollingBenchmark.java:59)
The last line repeats itself a huge number of times. Line 59 in my code represents the return statement from the try block (return temp + ...). I am using IntelliJ with a Java 11 SDK and never ever met this error before.
It is obviously a concatenation problem, because if I'm just outputting a simple string (without any + operators), everything seems to work fine. The string concatenation works outside this method.
I am not going to also display the other method (findNextPrime()), because I feel like wasting too much space and making the question more complex as it already is. If you need more details, please leave a comment and I will surely add the other method, too (or what you're asking for).
Related
This is my first UVa submission so I had a few problems in the way. The biggest hurdle that took my time so far was probably getting all the formats correctly (I know, shouldn't have been too hard but I kept getting runtime error without knowing what that actually meant in this context). I did finally get past that runtime error, but I still get "Wrong answer."
Listed below are the things I've done for this problem. I've been working on this for the last few hours, and I honestly thought about just dropping it altogether, but this will bother me so much, so this is my last hope.
Things I've done:
considered int overflow so changed to long at applicable places
got the whole list (1-1000000) in the beginning through memorization for computation time
submitted to uDebug. Critical input and Random input both show matching output.
submitted to to UVa online judge and got "Wrong Answer" with 0.13~0.15 runtime.
Things I'm not too sure about:
I think I read that UVa doesn't want its classes to be public. So I left mine as class Main instead of the usual public class Main. Someone from another place mentioned that it should be the latter. Not sure which one UVa online judge likes.
input. I used BufferedReader(new InputStreaReader (System.in)) for this. Also not sure if UVa online judge likes this.
I thought my algorithm was correct but because of "Wrong answer," I'm not so sure. If my code is hard to read, I'll try to describe what I did after the code.
Here is my code:
class Main {
public static int mainMethod(long i, int c, List<Integer> l) {
if (i==1)
return ++c;
else if (i%2==0) {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i/2, c, l);
}
}
else {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i*3+1, c, l);
}
}
}
public static int countMax(int x, int y, List<Integer> l) {
int max=0;
if (x>y) {
int temp = x;
x= y;
y = temp;
}
for (int i=x; i<=y; i++) {
if (l.get(i)>max)
max = l.get(i);
}
return max;
}
public static void main(String[] args) {
List<Integer> fixed = Arrays.asList(new Integer[1000000]);
for (long i=1; i<1000000; i++) {
fixed.set((int)i, mainMethod(i,0,fixed));
}
String s;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while ((s = br.readLine())!=null) {
int x = -1;
int y = -1;
for (String split : s.split("\\s+")) {
if (!split.equals("\\s+") && x==-1) {
x = Integer.parseInt(split);
} else if (!split.equals("\\s+") && x!=-1) {
y = Integer.parseInt(split);
}
}
if (x!=-1&&y!=-1)
System.out.println(Integer.toString(x) + " " + Integer.toString(y) + " " + Integer.toString(countMax(x,y,fixed)));
}
} catch (IOException e) {
} catch (NumberFormatException e) {
}
}
}
I apologize for generic names for methods and variables. mainMethod deals with memorization and creating the initial list. countMax deals with the input from the problem (15 20) and finding the max length using the list. The for loop within the main method deals with potential empty lines and too many spaces.
So my (if not so obvious) question is, what is wrong with my code? Again, this worked perfectly fine on uDebug's Random Input and Critical Input. For some reason, however, UVa online judge says that it's wrong. I'm just clueless as to where it is. I'm a student so I'm still learning. Thank you!
Haven't spotted your error yet, but a few things that may make it easier to spot.
First off:
int goes to 2^31, so declaring i in mainMethod to be long is unnecessary. It also states in the problem specification that no operation will overflow an int, doesn't it? Getting rid of the extraneous longs (and (int) casts) would make it easier to comprehend.
Second:
It's probably clearer to make your recursive call with c + 1 than ++c or doing c++ before it. Those have side effects, and it makes it harder to follow what you're doing (because if you're incrementing c, there must be a reason, right?) What you're writing is technically correct, but it's unidiomatic enough that it distracts.
Third:
So, am I missing something, or are you never actually setting any of the values in the List in your memoization function? If I'm not blind (which is a possibility) that would certainly keep it from passing as-is. Wait, no, definitely blind - you're doing it in the loop that calls it. With this sort of function, I'd expect it to mutate the List in the function. When you call it for i=1, you're computing i=4 (3 * 1 + 1) - you may as well save it.
I have been working on a few projects lately that use a flood fill on a 2D array to create a grid map for a game.
Part of the flood fill algorithm I am using grabs the neighboring "cells" in the grid and floods them if they are an open space and ignores them if they are not.
However, because I am grabbing neighbor cells, I am grabbing items from the array relative to the current cell like this: grid[y][x-1].
Obviously, when x == 0 an out of bounds error is thrown. In order to address this I have been using a conditional statement to check that the index I am accessing is in the array. Like this:
if(x - 1 >= 0){do what I need to that neighbor}
I know I can also address the error by using a try catch.
However, I am not sure which is the proper solution.
There are a few specific questions I have:
1) Does using the conditional method to prevent an error from occurring, require more overhead and create less efficiency? (I may be flooding thousands of cells)
2) How exactly does the catch block work? Is it conditionally checking for errors in the background some how?
I also made a very small demo code to show you exactly what I am talking about, just scaled down:
public static void main(String[] args) {
//declare our test array and initialize size 3
String [] testArray = new String[3];
//This is here for one of the methods I have been trying to avoid errors on
int indexAdjuster = 5;
//this the index of the array we are adjusting
int i = 0;
//now throw an error! uncomment to confirm there is an error if you want
//testArray[i-indexAdjuster] = "error";
//testArray[i+indexAdjuster] = "error";
//IGNORE the error with a try catch
try{
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0-indexAdjuster] = "error";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0+indexAdjuster] = "error";
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("There was an error, but I ignored it");
}
//PREVENT an error with a condition test
//it first checks if the adjusted index is at least 0
//then it checks if the adjusted index is less than the length of the array
if(i - indexAdjuster >= 0 && i + indexAdjuster < testArray.length){
//this would result in an out of bounds exception below index 0 (-5 specifically)
testArray[0 - indexAdjuster] = "This would be an error, but it is prevented";
//this would result in an out of bounds exception above index 2 (5 specifically)
testArray[0 + indexAdjuster] = "This would be an error, but it is prevented";
}else{
System.out.println("We just prevented the error");
}
System.out.println("Test Complete");
}
It depends, specifically on what you primary focus is: Speed or clean code.
If the error condition occurs rarely and the check is costly, catching an exception may be cheaper than checking beforehand. This conflicts the commonly accepted rule that catch blocks should not be used for regular flow control. Exceptions should be used to catch unexpected error conditions, an index outside an array is hardly unexpected.
The test can also be extracted into a separate method, making the code easier to read:
static boolean isValidIndex(String[] array, int i) {
return i >= 0 && i < array.length;
}
Or use a resilient access method:
static String getIndex(String[] array, int i) {
return i >= 0 && i < array.length ? array[i] : null;
}
(You may want to replace null with a constant value indicating an invalid value).
In your code you can simply use the getIndex() method for whatever index you calculated and act on the value it returns instead of the index. Same can be done for assigning to an index, if its appropiate to just ignore attempted assignments to non-existing indices:
static void setIndex(String[] array, int i, String value) {
if (i >= 0 && i < array.length)
array[i] = value;
}
The main issue you face is deciding if an out-of-bounds condition is just a normal case that has a reasonable default handling option or if it represents a real error that warrants aborting the method or program.
If its a real error condition, don't prevent it, don't catch it. Let it throw and bubble up the call stack. Whatever caller level initiated the whole action should be the one that responds to the execption. Its important to decide sensibly who is responsible for the handling, a deep-down detail method has often not enough information to make a reasonable decision what an error means - in those cases assign the responsibility to the caller (repeat until the caller can make the decision).
Using if statement to check your boundaries cause lots of overhead in each loop iteration.
I suggest you allocate a bigger array by 1 like:
String [] testArray = new String[3+1];
This cause that you don't need any if condition.
In response to your question about exception handling, it does not run any condition in background. It runs your code and after causing access violation determines you catch clauses.
I tried to write code to get the largest prime factor of a big number (in this case, 600851475143).
After writing four different methods (2 to show results, and 2 with other calculations), I have written the program class, and tried to run it.
When I run it, the result should appear in the console, but nothing shows up. I tried to make the variable that should be printed public, and just print it manually, but it didn't work. Eventually, I wrote the simplest System.out.print() command in the main method, but nothing appeared in the console.
I have no idea what the problem is. Does anyone here have a clue?
The class:
public class Problem3 {
public float sum1;
public float sum2;
private float num = 600851475143f;
public void methodGuy(){
while(sum1==0){
for(int i=2; i<num/2; i++){
if(num%i==0){
sum1=num/i;
} else {}
}
}
}
public void show1(){
System.out.println("the result of Guys method is: " + sum1);
}
public void methodOr(){
for(int i=2; i<num/2; i++){
for(float x=num/2; x>2; x=x-1){
if(i*x==num){
sum2=x;
}
}
}
}
public void show2(){
System.out.println("the result of Ors method is: " + sum2);
}
}
The program class:
public class Program {
public static void main(String[] args) {
Problem3 x = new Problem3();
x.methodGuy();
x.show1();
x.methodOr();
x.show2();
}
}
methodGuy will never terminate because int's can't get that big.
The largest possible value of an int is 2147483647. If your int is that number, and you add one to it, the number will wrap around and become negative. So after i++, the next value will be -2147483648. Since the loop will continue as long as i is less than 600851475143/2 = 300425237071.5, and since i will always be less than that, your loop is infinite.
Best would be to make both i and num have type long, instead of int or float. Even if you do that, your loop will probably run for a very long time.
In fact, if there are no factors, the loop will be infinite, because sum will never be set to something other than 0, and then since you say while (sum==0), the loop will just start over again and do the same thing infinitely. So aside from the wraparound problem, your algorithm still needs work.
Further note: You definitely do not want to use float for this, because the number 600851475143 cannot be represented exactly. The actual value of num will be 600851480576.
I am trying to learn recursion in Java and have an array that takes in continuous input until the Scanner reads in a 0.
From there I have a method that (attempts) to calculate the number of positive integers in the array using recursion. This is the first recursive function I have ever written and I keep getting a stackoverflow error.
I have read tutorials and I still can't wrap my head around the basic understanding of recursion.
public class reuncF {
private static int start = 0;
private static int end = 98;
public static void main(String[] args) {
input = input.nextDouble();
list[i] = numInput;
computeSumPositive(numList, count);
}
}
return positives += solve(numbers, count++);
}
}
You forgot to stop your recursion!
There has to be some case where computeSumPositive returns without calling itself again. Otherwise it'll just keep going forever, never getting back to you.
If you did it with a loop, the loop would look like this:
int positives = 0;
for (int i = 0; i < numList.length; ++i) {
if (numList[i] > 0) {
positives++;
}
}
To do that recursively, you just find out what are the variables used in the loop. They are i, numList and positives.
computeSumPositive(int i, double[] numList, int positives)
Then we take a look at what the loop does. First, it checks whether we went too far,
so our recursive function should do that too. It'll have to return instead of just falling through like the loop does. And obviously, it must return the result:
{
if (! (i < numList.length))
return positives;
The loop then does the test and maybe increments positives, so the recursive function should also do that:
if (numList[i] > 0) {
positives++;
}
At the end of the loop, i is updated:
i++;
The loop just starts over, but the recursive function will have to call itself. Of course, we want it to use the new value of i and positives, but fortunately we updated those, so now we can just do:
return computeSumPositives (i, numList, positives);
}
The tricky bit is that the values i, numList, and are local to each call. Each invocation of computeSumPositives can see only the arguments it were given. If it changes them, none of the other invocation can see that change.
EDIT: So if we, for reasons we can only speculate about, wanted desperately for computeSumPositive to take only 2 parameters, we would have to "split up" positives across each invocation. Each invocation knows whether or not its number was positive or not; all we have to do is add them. Then it looks like this:
computeSumPositive(int i, double[] numList)
{
if (! (i < numList.length))
return 0; // I didn't find any at index i
if (numList[i] > 0) {
// Theres one I found + however many my later
// invocations will find.
return 1 + computeSumPositive (i+1, numList);
} else {
// I didn't find any, but my later invocations might.
return computeSumPositive (i+1, numList);
}
}
I find it helpful, when dealing with recursion, to figure out the termination case first.
It looks like you are treating 'count' as an index. So you could check if your at the last index in the array, if so and if the value is positive return a 1, if the value is non-positive return a 0 - dont recurse anymore.
If your not at the last index, and the value is positive return a 1 + the recursive function call, or if the value is non-positive just continue to recurse.
This will still cause a stack overflow for large arrays.
The value of count++ is the same as the value of count; the program uses the value and then increments it. But the result is that computeSumPositive keeps calling itself with the same value of count, which leads to infinite recursion. Note that each time computeSumPositive calls another computeSumPositive, each call has its own copy of the parameters (like count) and the local variables; so incrementing one computeSumPositive's copy of count has no effect on the value of count used by other recursive calls.
Change count++ to count + 1, and also add a way to halt the recursion. (At some point, you will be calling computeSumPositive to look at zero integers, and at that point, it should just return 0 and not call itself. You need to think about: how do you test whether you've reached that point?)
I have the following code:
if (maxLength>=0 && (++totalLength > maxLength))
throw new IllegalStateException("Form too large");
in a loop where bytes are read from byte array input stream. The maxLength is set to Integer.MAX_VALUE so I think that the condition could never be true (and I'm not talking about the size of the byte array in input stream which I'm absolutely sure is not long enough). But I get the IllegalStateException thrown from that line!!! Now the real bummer is that when I put a breakpoint on that throw line, everything is ok. How the hell is this possible?
EDIT:
both variables are of type int
totalLength is a local variable, maxLength is a parameter
the debugger don't stop there AND the exception is not thrown at all, when there is a breakpoint on that throw line.
I actualy don't know why I'm suspecting parallelism, it's just because it's web application
I admit that using MAX_VALUE is very risky (in the next step I will try to decrease this limit), but I would expect some other execption than that in the success branch of if statement. And moreover that byte array used in input stream is really not long enough. This should be plainly impossible situation in JVM:-).
The code above is in jetty-util-7.1.5.v20100705.jar in the class UrlEncoded and I'm using it by calling
byte[] decodedBytes;
byte[] encodedBytes;
// v pripade url encoded requestu je potreba pouze odriznout
// jmeno falesneho parametru nesouciho kodovany blok
encodedBytes = Arrays.copyOfRange(content, "encdata=".length(), content.length);
decodedBytes = decodeBytes(request, encodedBytes);
// priprav desifrovany text jako vstupni proud
decodedInputStream = new ByteArrayInputStream(decodedBytes);
// pokud je request url encoded je potreba jej manualne parsovat
// pro potreby funkci vracejicich parametry
UrlEncoded.decodeTo(decodedInputStream, parameters, request.getCharacterEncoding(), Integer.MAX_VALUE);
Are there any parallel issues with Integer.MAX_VALUE
No, this is most likely not due to any race-conditions (unless you have other threads modifying maxLength or so).
According to the JLS on integer is larger than Integer.MAX_VALUE so this is either due to a bug in your VM or based on the false assumption that maxLength is indeed Integer.MAX_VALUE.
The maxLength is set to Integer.MAX_VALUE so I think that the condition could never be true
Make sure totalLength is not a long.
(The snippet below always throws the exception.)
int maxLength = Integer.MAX_VALUE;
long totalLength = 2147483647;
if (maxLength>=0 && (++totalLength > maxLength))
throw new IllegalStateException("Form too large");
If it's not reproducible with the debugger, just give a more informative error message to the exception, for instance: "Form too large: " + totalLength + " is larger than " + maxLength
Are you sure you want to increment totalLength before the comparison, rather than after? If your totalLength going into that statement is equal to maxLength, the exception will be thrown... is that a possible scenario?
Try totalLength++ instead.
Just a thought. Hope this helps.
Now the real bummer is that when I put a breakpoint on that throw line, everything is ok
Do you mean the debugger doesn't stop there?
From your question title it seems you suspect a racing condition (multithreading) issue.
How are the variables defined?
Could you post some more code?
Could maxLength be modified elsewhere? Or is it final?