What is StackOverflowError? - java

I'm attempting to generate a random four digit number with no repeating digits. I have a method to generate the number and two to check for length and repetition. It compiles and works as expected, however, occasionally, I will get a StackOverflowError while it is running. Here is the block of code where it seems to be having a problem with:
//ensures that generated pattern is four digits long
public void randomCheck(){
int patternNum = Integer.parseInt(pattern);
if(patternNum<1000){
numGen();
}
else{
repeatCheck();
}
}
//ensures that pattern is unique
public void repeatCheck(){
solutionNumber();
if((secondSolnDigit==firstSolnDigit)||(firstSolnDigit==thirdSolnDigit)||
(firstSolnDigit==fourthSolnDigit)||(secondSolnDigit==thirdSolnDigit)||
(secondSolnDigit==fourthSolnDigit)||(thirdSolnDigit==fourthSolnDigit)){
numGen();
}
else{
return pattern;
}
}
//generates random number
public void numGen();{
Random rand = new Random();
int randomNum = rand.nextInt(10000);
String patternString = Integer.toString(randomNum);
pattern = patternString;
randomCheck();
}

The stack overflow error happen when a there is too many method call in each other. It generally happen in recursive methods. Here it happens because you call numGen() from randomCheck() and repeatCheck() then numGen() call back randomCheck().
The solution here is to test in a while loop, remove you method randomCheck() and replace your code by:
//ensures that pattern is unique AND four digits long
public void repeatCheck(){
solutionNumber();
int patternNum = Integer.parseInt(pattern);
while((secondSolnDigit==firstSolnDigit)||(firstSolnDigit==thirdSolnDigit)||
(firstSolnDigit==fourthSolnDigit)||(secondSolnDigit==thirdSolnDigit)||
(secondSolnDigit==fourthSolnDigit)||(thirdSolnDigit==fourthSolnDigit) || patternNum<1000){
numGen();
}
return pattern;
}
//generates random number
public void numGen();{
Random rand = new Random();
int randomNum = rand.nextInt(10000);
String patternString = Integer.toString(randomNum);
pattern = patternString;
}
Moreover why do you cast your integer in string and then cast it back in integer, can't you just use the int as it is generated? and convert it after if you really need it as a string.
Hope this helped.

StackOverflowError is when you have to many method calls stacked on one another. There is a limit in Java to how many method calls can be stacked on one another.
You are calling randomCheck() from your numGen() method and calling numGen() from your randomCheck() method this appears to be the problem. Your code is probably chasing it's own tail. If numGen() is not called from randomCheck() then repeatCheck() is which also calls numGen().
It may work fine sometimes if it reaches the end of method calls before the stack runs out of space. But in some cases it is making more method calls than others adding more calls to the stack and eventually running out of space. That is why it works sometimes and not others.
You could try using a loop to accomplish the same thing. This way you won't have to worry about StackOverflowError.

Related

Implementing Ackermann Function by Java with BigInteger support

I'm getting StackOverflowError (Exception in thread "main" java.lang.StackOverflowError) for the following code. But the program works fine for m=3, n=3 (or other lower values) but does not work for m=4 and n=2 or 3.
public class AckermannFunction
{
static BigInteger One = BigInteger.ONE;
static BigInteger Zero = BigInteger.ZERO;
static BigInteger ackmnFun(BigInteger m, BigInteger n)
{
if (m.equals(Zero))
return n.add(One);
if (n.equals(Zero))
return ackmnFun(m.subtract(One), One);
return ackmnFun(m.subtract(One), ackmnFun(m, n.subtract(One)));
}
public static void main(String[] args)
{
BigInteger m = new BigInteger("4");
BigInteger n = new BigInteger("3");
System.out.println(ackmnFun(m, n));
}
}
There are too many recursive calls I understand. Is there any way to get rid of this error?
Thanks.
Rather than doing this recursively, you could approach it as a dynamic programming problem, and construct a table of values from the bottom up. Then rather than making recursive calls, you simply reference your table to create the next entry.
I've found a solution of my question by myself. I want to share it with you.
Since the Ackermann function calls itself for so many times even for a very low value of m & n, what I did, I added few more terminating condition up to m=3 and n=3 (to minimize recursive calls). And the tricks worked. I found initial values by running the original recursive function and then added all these as terminating condition.
The program finds the Ackermann(4,2) in a few seconds now. The answer is very long containing 19729 decimal digits.

Adding a given String to itself a number of given times

In an arbitrary class, I decided to make a method for making a divider based on the character you want the divider made out of, and the amount you want.
public String divider(String s, int amount){
StringBuilder repeated = new StringBuilder();
for(int i = 0; i < amount; i++){repeated.append(s);}
return repeated.toString();
}
The method is defined in the Catalog class.
And I'm calling it as
this.divider("-", 10);
in the toString() of the class. And I'm calling it in the main method as
mainCat.divider("-", 10)
mainCat is a Catalog object.
I've tried a bunch of different ways of multiplying a string by itself in a loop to make copies of itself but they all come up blank for me. Any suggestions would be appreciated, thanks!
You better just use StringUtils.repeat(str, count).

How can I maintain probability across multiple executions in Java

Firstly I am not the greatest with Math, so please excuse any ignorance relating to that. I am trying to maintain probability based randomness across multiple executions but I am failing. I have this input in a JSONObject
{
"option1": 25,
"option2":25,
"option3" :10,
"option4" :40
}
This is my function that selects a value from the above JSONObject based on the probability assigned:
public static String selectRandomoptions(JSONObject options) {
String selectedOption = null;
if (options != null) {
int maxChance = 0;
for (String option : options.keySet()) {
maxChance += options.getInt(option);
}
if (maxChance < 100) {
maxChance = 100;
}
Random r = new Random();
Integer randomValue = r.nextInt(maxChance);
int chance = 0;
for (String option : options.keySet()) {
chance += options.getInt(option);
if (chance >= randomValue) {
selectedOption = options.toLowerCase();
break;
}
}
}
}
the function behaves within a reasonable error margin if I call it x amount of times in a single execution ( tested 100+ calls), the problem is that I am running this every hour to generates some sample data in an event-driven app to verify our analytics process/data but we need it to be somewhat predictable, at least within a reasonable margin?
Has anyone any idea how I might approach this? I would rather not have to persist anything but I am not opposed to it if it makes sense or reduces complexity/time.
The values returned by Random.nextInt() are uniformly distributed, so that shouldn't be a problem.
I you would like to make random results repeatable, then you may want to use Random with seed.
Rather than create a new Random() object each time you want a new random number, just create the Random object once per run, and use the Random.nextInt() object once per run.
Looking at the documentation of Random() constructor,
This constructor sets the seed of the random number generator to a
value very likely to be distinct from any other invocation of this
constructor.it only guarantees it to be different
that's a bit of a weaker contract than the number you get from nextInt().
If you want to get the same sequence of numbers on each run, use the Random(long seed) or the setSeed(long seed) method of the random object. Both these methods set the seed of the generator. If you used the same seed for each invocation it's guaranteed that you will get the same sequence of numbers from the generator.
Random.setSeed(long).

Extend java.util.Random to control generation of numbers

Hello I have the following tasks:
First, I am given this code that uses a method to generate random numbers 100 times:
public class Q3 {
public static void printDiceRolls(Random randGenerator) {
for (int i = 0; i < 100; i++) {
System.out.println(randGenerator.nextInt(6) + 1);
}
}
public static void main(String[] args) {
Random man = new Random();
printDiceRolls(man);
}
}
Second, I am asked to make a class LoadedDice that extends the Random class:
public class LoadedDice extends Random {
// instance variables - replace the example below with your own
public int nextInt(int num) {
// code right here
return 3;
}
}
Then I am asked to override the public int nextInt ( int num ) and do the following
Override the public int nextInt(int num) method such that with a 50%
chance, the new method always returns the largest number possible
(i.e., num-1), and with a 50% chance, it returns what the Random's
nextInt method would return
I do not quite understand what my overridden method should do in this case.
Suggestions?
Use another Random instance to give you a 50% chance (e.g. nextInt(100) >= 50) then based on that return a constant or a real random.
I guess one way to do this is to use (another?) random number generator with a uniform distribution and set it to return 0 or 1. The 0/1 would be the 50% for you to make your decision upon.... either returning super.nextInt or the max number.
To me, it looks like the nextInt(int) function comes up with a number between 1 and the input. In the root Random class, this function finds a random number within that range. What they want you to do is change that so that half the time it will return a random number in the range, but the other half the time it will give the maximum number.
In the example they gave, you're rolling a dice, so the range is 1-6. Normally, nextInt will find a random number between 1 and 6. But your new function will only do that half the time. The other half the time, it will return 6.
I have an idea on how you can implement that, but it seems like it would be cheating to go that far. ^^;
if(super.nextBoolean())
return num-1;
return super.nextInt(num);
if num<Integer.MAX/2, we can
int x = super.nextInt(num*2);
return Math.min(x, num-1);

Testing a method producing a random result

I want to test this method:ArrayList<File> songs;
public void playRandomSong()
{
Random random = new Random();
int iNextSong = random.nextInt(songs.size());
File songToPlay = songs.get(iNextSong);
if (mediaPlayer != null && mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer = new MediaPlayerImpl(songToPlay, new WhenDone());
mediaPlayer.play();
currentSong = songToPlay;
}
I'm thinking in this way: Run the method multiple times and see if it returns one of the elements more than once. But how would I write that in code?
Random does not guarantee that it will not return the same value twice...
So you can not test "see if it returns one of the elements more than once"
If you need that you will have to implement a Set around the Random, but be aware of the Birthday paradox...
I think you have 2 options:
1 : You may try to seed your Random, so you can predict the sequence...
2 : Remove the Random and make use of the [Collections.shuffle][1] to shuffle you arrayList
With Option 1 you will have to change the signature of your method.
With Option 2 you will also play every song once.
Instead of creating a RNG in your method
public void playRandomSong() {
Random random = new Random();
...
}
you should pass the source of randomness in (this is called dependency injection)
public void playRandomSong(Random random) {
...
}
and then you can generate a Random instance with a known seed in your unit test to get repeatable but typical results.
public void testPlayRandomSong() {
Random random = new Random(0xd5021e90339050ab);
// Test that 1000 runs plays each song roughly the right number of times.
...
}
I see another problem in your code: if you want to play songs in random order you are doing that in wrong way. This algorithm should not repeat song until all songs in list are played. To achieve that there is an algorithm called Knuth shuffling. You can take it from Collections class: java.util.Collections#shuffle.
Here is an article on randomness testing that you might find useful:
http://beust.com/weblog/2012/02/20/various-ways-to-get-randomness-wrong/

Categories