I have a very strange bug that I am trying to fix. I will try my best to explain it.
I have a class, and in that class I have a method that picks a random number.
The random number generation has to generate the exact same sequence of numbers every time I run the application (different numbers, but appear in the same order no matter when I run the app).
Therefore I need to use seeds.
My code looks something like this:
public class Tree{
Random rand = new Random(12345);
///...code...///
public Tree randomNode() {
//HERE IS THE ERROR
int r = rand.nextInt(this.size);
if (r == 0) {
return this;
}
else if (left != null && 1 <= r && r <= left.size) {
return left.randomNode();
}
else {
return right.randomNode();
}
}
}
I have a helper class that uses this, it looks a bit like this:
public Crossover(Tree p1, Tree p2)
{
Tree subtreeP1 = p1.randomNode();
Tree subtreeP2 = p2.randomNode();
}
My main method looks a bit like this:
for(i=0;i<cross;i++)
{
Crossover c = new Crossover(p1,p2);
}
During the first loop in the main method, the numbers for r generate randomly and are fine. However, on the 2nd loop (and all that follow) is where I encounter the problem.
The problem is on the line int r = rand.nextInt(this.size); - After the 2nd loop I ALWAYS get 0 no matter what.
If I remove the seed, all works well. If I include the seed, I start getting 0 ALWAYS after the first loop.
How can I continue using a seed, but get random numbers? And what am I doing wrong?
**EDIT: **
this.size refers to the size of my tree. I have ensured it is NOT zero when I get r to be 0.
ALSO I would like to point out, that when I simply remove the number seed, it works fine, and random number generation works fine. When I add the seed, I have the problem.
EDIT #2
Ok, so as requested, I've put together a little program that illustrates my problem. Just run it as is. Once with the seed and once without.
import java.util.*;
public class Problem{
public static void main(String args[])
{
for(int i=0; i<100; i++)
{
Clas c1 = new Clas();
Helper h = new Helper(c1);
System.out.println(h.getR());
}
}
}
class Helper
{
int r;
Helper(Clas c)
{
r = c.method();
}
public int getR()
{
return r;
}
}
class Clas
{
Random rand = new Random(1825897);
Clas()
{
}
public int method()
{
int r = rand.nextInt(10);
return r;
}
}
In the loop, you don't want to reset the Random Number Generator, I assume?
In the example, you could do:
Clas c1 = new Clas();
for(int i=0; i<100; i++)
{
Helper h = new Helper(c1);
System.out.println(h.getR());
}
In your original example, you seem to have multiple Tree instances, so you can't use this. But you can declare your Random static, so it is shared among all Trees:
static Random rand = new Random(1825897);
Try using the function Math.random() to generate your random number. Math.random() generates a random number between 0 and 1.
Related
I'm trying to implement a recursive shuffle method that will take nlog(n) time but am having major difficulty, given I am restricted to a single parameter and can't include the size of n in my params when calling the recursive method. I looked at the structure of a similar shuffling problem with different parameters and got the idea for how to structure the shuffling using Random, but I've spent way too much time trying to figure out how to implement this.
If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it? How would I go about either decrementing n for the purpose of managing the recursion, or modify a somehow to eventually end the recursion?
*Also, would declaring the objects in the indices like this cause a referential issue? If so, how would I fix this? I tried clone and couldn't get it to function within the requirements of the problem.
public static void shuffle(Object[] a) {
int n = a.length;
if (n == 0) {
return;
}
int d = (int) (Math.random() * (n-1)); //random index
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
shuffle(a);
shuffle(a);
}
***What I've started to implement which looks a lot more like it would work in nlogn time complexity, but not sure if it's right or how it would need to be finished...
public static void shuffle(Object[] a){
if(a.length == 1) return; //return if length = 1: base case
Object[] b = new Object[a.length/2]();
Random rand = new Random(0,a.length); //random index to swap
for(int i = 0; i < b.length; i++){
b[i] = a[rand]; //how do I make sure no index of a is
//repeated?
}
shuffle(b); //recursively call shuffle on b, dividing size by 2
for(int i = 0; i < a.length; i++){
a[i] = b[i]; //copy values from b to a (I guess you could use arraycopy)
}
}
If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it?
It does not have to be a global variable. You can create a class inside your method as follows. This should support any requirement that the implementation must be kept inside the publicly available method. Of course, you'll need to decide if this is in accordance with any other restrictions not mentioned in your question. I leave the actual algorithm up to you. But the array can be shuffled in-place in O(n).
public static void shuffle(Object[] a) {
class Shuffle {
private void recShuffle(Object[] ob, int n) {
// your shuffle algorithm here
}
}
Shuffle s = new Shuffle();
int n = ... // up to you
s.recShuffle(a, n);
}
So I was able to figure out a way to solve it this morning by implementing a helper method and moving most of my code there in case anyone ever comes across a problem like this:
//calls helper shuffle method
public static void shuffle(Object[] a) {
int n = a.length;
helperShuffle(a, n);
}
public static Object[] helperShuffle(Object[] a, int n) {
if (n <= 1)
return a; //base case: size of array is 1
Random rand = new Random(); //declare new random
int d = (rand.nextInt(n)); //random index < n
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
return helperShuffle(a,n-1);
}
I have been working to get the headcount variable to be random but cannot figure this out
public class Coin
{
private final int HEADS = 0;
private final int TAILS = 1;
private int face;
private static int seed =0;
private Random r;
public Coin ()
{
r = new Random(seed);
flip();
seed++;
}
public void flip ()
{
face = r.nextInt(2);
}
public int getFace()
{
return face;
}
public void setFace(int newFace)
{
face = newFace;
}
public boolean isHeads ()
{
return (face == HEADS);
}
public String toString()
{
String faceName;
if (face == HEADS)
faceName = "Heads";
else
faceName = "Tails";
return faceName;
}
public static void main(String[] args)
{
Coin myCoin = new Coin();
double randnumber =Math.random();
int headCount=0;
for (int i =1; i<=100; i++)
{
myCoin.flip();
if(myCoin.isHeads())
{
headCount++;
}
}
System.out.println("If I flip my coin 100 times, I get " + headCount + " heads.");
headCount =0;
for (int i =1; i<=100; i++)
{
Coin yourCoin = new Coin();
yourCoin.flip();
if(yourCoin.isHeads())
{
headCount++;
}
}
System.out.println("If I flip 100 coins, I get " + headCount + " tails.");
}
}
Whenever I Compile it and Run the program I get the same output which is
If I flip my coin 100 times, I get 47 heads.
If I flip 100 coins, I get 50 tails.
I dont understand how to make the 47 and 50 to be new random numbers each time you run the program. I have looked int Math.Random and other random variables but am unsure how to implement it into this program.
What you want is:
r = new Random(System.currentTimeMillis());
BTW: Random Numbers generators always start with the same number, given a certain seed.
For example, supposed the "random number" generator added 2 to find the next random number.
seed = 9
r(9) = 11 ; r(11) = 13 ; r(13) = 15.
However, a different seed will lead to a different string of numbers.
seed = 4
r(4) = 6 ;
Random numbers in computer programming aren't really random. They depend on a seed value. If you give it the same seed each time, you'll get the same sequence of "random" values each time.
If, instead, you use the empty constructor for Random, it will create a seed for you that is based on the current system nano time. In this way, you will mitigate the chance that you start with the same seed.
So, as others have already mentioned, either call the empty Random constructor, or create a pseudo-random seed yourself before creating a Random that takes the seed argument.
With all that said, it's probably best to assume the JDK implementers have already thought about how best to generate a seed for you, so you should just use the empty constructor.
If you want to see the Java source for the Random class, you can search for
grepcode java.util.Random.java
and see how the JDK implementers create the seed.
Solve the seed issue by declaring Random in the class directly instead in a method.
private Random r = new Random();
public Coin()
{
int x = r.nextInt();
flip();
}
Random random = new Random();
int numDigits;
int[] secretNumber = new int[numDigits];
public int[] convertNumToDigitArray(String number){
int[] numToDigitArray = new int[numDigits];
for (int i = 0; i<number.length(); i++){
numToDigitArray[i] = number.charAt(i);
}
return numToDigitArray;
}
public int getNumDigits(){
return numDigits;
}
public int[] getSecretNumber(){
return secretNumber;
}
public void setNumDigits(int numDigits){
this.numDigits=numDigits;
}
public void generateNewSecret(){
int number = random.nextInt(((int)Math.pow(10, numDigits) - ((int)Math.pow(10, numDigits-1)))) + ((int)Math.pow(10, numDigits-1));
int temporary = numDigits;
for (int i = 0; i < numDigits; i++){
secretNumber[i] = (int)(number/(Math.pow(10, temporary--))); //here's where the exception is thrown!
if (number < 10)
break;
number = number%((int)(Math.pow(10, temporary--)));
temporary--;
}
}
Hi all, I am stuck on a problem and need some help. I have written (and am debugging) a program that generates a number, puts that number in an array, and then compares a user guess to that number. The point I am stuck at is when the computer generates the number, the array I am putting it in is throwing an exception that the index is out of bounds. That must mean that (to my knowledge) the index is below zero. But when I run the program separately and check the index, it starts at 0. The method in question runs independently and generates the array without throwing the exception, but when it's called from the 'mother program' the exception is thrown. It points to the line in the code where the array is being filled inside a loop here.
Any help would be super appreciated :)
You need to ensure that numDigits always equals the number of elements in the secretNumber array:
public void setNumDigits(int numDigits){
this.numDigits=numDigits;
// Add this line
secretNumber = new int[numDigits];
}
Currently you can set numDigits to a value that is higher than the array size. This is what can lead to the error in the for loop on secretDigits limited by the numDigits.
So I am trying to test if a sequence of integers was randomly generated, but it doesn't work...
this is what I've got so far:
public static void main(String[] args) {
Random r = new Random();
int[] sequence = { r.nextInt(), r.nextInt(), r.nextInt() };
System.out.println(isRandomSequence(sequence));
}
public static boolean isRandomSequence(int[] sequence) {
for (long seed = 0; seed < Long.MAX_VALUE; ++seed) {
Random r = new Random(seed);
long tries = 0;
for (int i = 0; tries < Long.MAX_VALUE; ++tries) {
if (sequence[i] == r.nextInt()) {
if (++i == sequence.length) return true;
} else {
i = 0;
}
}
}
return false;
}
Edit: to clarify; I want to know if, for instance the sequence { 4, 5, 6 } was generated by the random number generator. For starters limiting the testing to the java.util.Random (would be nice to have a general solution though if it's possible).
Apart from being intractable, your brute-force technique will only detect a pseudorandom sequence generated by java.util.Random, by far not the only option to generate pseudorandom numbers. Also note the word pseudo: they are not really random, that is why you think you can detect the sequence.
Detecting whether a sequence is truly random is theoretically impossible: the best you can do is perform a barrage of pattern-detecting tests in order to eliminate certain possibilities. There will always be nonrandom sequences that escape detection.
I should also note that there is definitely nothing to say about a sequence of just three integers. I am pretty sure that the output of java.util.Random contains all possible three-integer sequences.
Random only has 2^48 seeds. This means you "only" need explore 2^48 seeds from the start. no more.
All the same, exploring 2^48 seeds will take hours or days to run.
As this is very cpu intensive you could look at using all the CPUs you have available ;)
I think you're thinking about the way seed works incorrectly. That might explain why you aren't getting random sequences.
You don't seed every time. You instantiate the Random with the seed at the start of your process and hang onto it.
If you create a Random inside a method call, with a new seed every time you want a sequence, you're definitely doing it wrong.
I'll bet this works:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
* RandomSequenceGenerator
* #author mduffy
* #since 12/12/12 4:38 PM
*/
public class RandomSequenceGenerator {
private Random random;
public static void main(String[] args) {
RandomSequenceGenerator generator = new RandomSequenceGenerator();
int numSequences = ((args.length > 0) ? Integer.valueOf(args[0]) : 10);
int lenSequence = ((args.length > 1) ? Integer.valueOf(args[1]) : 3);
for (int i = 0; i < numSequences; ++i) {
System.out.println(generator.createRandomSequence(lenSequence));
}
}
public RandomSequenceGenerator() {
this(System.currentTimeMillis());
}
public RandomSequenceGenerator(long seed) {
this.random = new Random(seed);
}
public synchronized List<Integer> createRandomSequence(int length) {
List<Integer> sequence = new ArrayList<Integer>(length);
for (int i = 0; i < length; ++i) {
sequence.add(this.random.nextInt());
}
return sequence;
}
}
How do I create the method RandomArray and let it take in an integer n and return an ArrayList of Integers that consist of n random numbers between 0 and 255.(in other words: let the returned array be of size n)???
(I am using Java Eclipse)
I have created the RandomArray, however I do not know how to put it in an ArrayList, this is what I've got so far:
import java.util.Random;
public class Lab6 {
public static void main(String[] args) {
Random random = new Random();
int[] n = new int[1];
for( int i = 0 ; i < n.length ; i++ ) {
for ( int i1 = 0 ; i1 < n.length ; i1++ ) {
n[i1] = random.nextInt(255);
}
}
for( int a : n ) {
System.out.println( a );
}
}
}
ArrayLists work in much the same way as arrays, except they can grow (or shrink) as you want and do not support access/retrieval via the [] operator (i.e. you can't do n[i1] on an ArrayList). Instead, use its add() method to add elements to it and get() method to access elements.
You mean something like this:
public ArrayList<Integer> randomArrayList(int n)
{
ArrayList<Integer> list = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < n; i++)
{
list.add(random.nextInt(255));
}
return list;
}
Try something like this
private ArrayList<Integer> randomArray(int size){
Random random = new Random();
ArrayList<Integer> newArrayList = new ArrayList<Integer>();
for(int i=0; i<size; i++){
int next = random.nextInt(256);
newArrayList.add(next);
}
return newArrayList;
}
Main method contains an example usage
import java.security.*;
import java.util.*;
public class Util {
public static void main(String[] args) {
int n = 15;
ArrayList<Integer> integers = RandomArray(n);
for (Integer integer : integers) {
System.out.println(integer);
}
}
private static ArrayList<Integer> RandomArray(int n) {
Random rand = new SecureRandom();
byte[] b = new byte[n];
rand.nextBytes(b);
Integer[] ints = new Integer[b.length];
for (int i = 0; i < b.length; i++) {
ints[i] = b[i] & 0xFF;
}
return new ArrayList<Integer>(Arrays.asList(ints));
}
}
This is more than you asked for, but it's tangentially related, and might help people coming across this question.
When you want an ArrayList of random integers, you often really just need some random numbers, and don't really need them stored anywhere. In such a case, you likely can get away with just an Iterator<Integer> that returns a stream of random integers, as many as you need. This is very easy to do with the Guava library (which nowadays should be part of every Java codebase).
You can easily define an Iterator<Integer> that gives you as many random ints (or any other data type you want) as you ask for:
public static final Iterator<Integer> RAND_INT_ITER =
new AbstractIterator<Integer>() {
#Override
protected Integer computeNext() {
return ThreadLocalRandom.current().nextInt();
}
};
Or if you want to use the Random.nextInt(int max) method:
public static Iterator<Integer> randIntIterator(final int max) {
return new AbstractIterator<Integer>() {
#Override
protected Integer computeNext() {
return ThreadLocalRandom.current().nextInt(max);
}
};
}
There's no issue with calling this method wherever you need it, since it stores no state you're not wasting time or space computing anything, and the garbage collector will clean it up for you when you're done. We use ThreadLocalRandom to ensure these are thread-safe and avoid constructing new Random objects all over the place (and the potential data-race conditions that introduces, though newer versions of Java are pretty smart about that). You could just as easily use an existing Random object if that made more sense.
Some examples:
// print random ints until we see one that's divisible by 100
while(true) {
int rnd = RAND_INT_ITER.next();
System.out.println(rnd);
if(rnd % 100 == 0) {
break;
}
}
// Get an iterator of exactly 10 random ints, [0,255)
Iterator<Integer> tenRandInts = Iterators.limit(randIntIterator(255), 10);
while(tenRandInts.hasNext()) {
System.out.println(tenRandInts.next());
}
// Note that the returned iterator above is still one-use, if you need to iterate
// Over the same numbers more than once, put them in a list first
// It's not a good idea to simply convert an Iterator into an Iterable, see:
// http://stackoverflow.com/a/14711323/113632
List<Integer> randIntLs = ImmutableList.copyOf(
Iterators.limit(randIntIterator(255), 10));
for(int rnd : randIntLs) {
System.out.println(rnd);
}
for(int rnd : randIntLs) {
System.out.println(rnd);
}
Using this pattern for random data generation will often make your code cleaner, leaner, and easier to read. Give it a try :)