I am trying to make a program to construct a Maze (a classic exercise in Java) and I want to my method to generate the maze to recieve a seed for the aleatory number generator that is used to generate this. This is required because I want the program to generate the same maze everytime I enter the same seed.
But, with some seed values, more values looks like to have more probability than others.
I mean, suppose that I set a random object with a given seed and use it to generate integers between [0, 4) and this is used as criteria to build the maze. The sequence generated is so characteristic that the maze is just too easy. Is I just dont set any seed, a good maze is generated.
The integers part are just an example. I could use an uniform and divide it 4 regions: [0, 0,25), [0,25, 0.5), [0.5, 0.75), [0.75, 1)
Is there a way to modify that seed so that the behavior of the random number generator will be the same for the same seed and mantain the good "mixture" of the numbers? I mean, how can I generate the same numbers setting a seed such that they are evenly distributed in this intervals?
Thanks!
You can try this to make sure the numbers are 'random', but uniformly distributed over [0, 1), [1, 2), [2, 3) and [3, 4):
Random random = new Random(seed);
int count = 200; // or another number, just how many you need
List<Float> numbers = new ArrayList<Float>(count);
for (int i = 0; i < count; i++) {
numbers.add(random.nextFloat() + (i % 4));
}
Collections.shuffle(numbers);
Related
I'm working on an android graphics app, and at some point in the code, I need to divide lets say, a rectangle's width into 5 random sizes.
I have my randomintegerfunction(int min, int max) in my activity, but that can help me divide it into 2 parts.
How do I go about dividing an integer, lets say 100, into 5 random parts, so that the first one or two parts arent always the biggest, then I subdivide for the third, fourth and fifth parts?
Right now, I am know I can try to implememt it using my random integer generator,but the issue, I think is that I'd have to use some forced divisions, like dividing the first 70% of the integer into 2 parts, then dividing the remaining 20% into two parts, to make a total of 5 parts, but such a method would always make the first part be bigger than the fifth part, which I'd like to avoid...to make it truly random.
What I'd like, for example...
the first part to potentially be 7,
second part 25,
third part 5,
fourth part 40,
fifth/last/remaining part 23. To add up to 100 (or any integer).
I am not sure about how to write the logic of such a function...so please if you have any ideas of how to implement a function that randomly divides an integer into 3 or 4 or 5 or 6 truly random sizes/parts, please enlighten me!
Thanks for your time!
You could randomly select from the amount remaining.
int[] nums = new int[5];
int total = 100;
Random rand = new Random();
for (int i = 0; i < nums.length-1; i++) {
nums[i] = rand.nextInt(total);
total -= nums[i];
}
nums[nums.length-1] = total;
Arrays.sort(nums);
This will select a random number and ensure the sum is always the same. The last sort ensures they are in ascending order.
A simple algorithm is to put the numbers 1-99 into a list, shuffle them, and take the first 4 elements as your "split points", i.e. positions at which to divide the number range.
List<Integer> splitPoints =
IntStream.rangeClosed(1, 99)
.boxed().collect(Collectors.toList());
Collections.shuffle(splitPoints);
splitPoints.subList(4, splitPoints.size()).clear();
Collections.sort(splitPoints);
Now, you have 4 randomly-placed split points. The ranges go from:
0 -> splitPoints.get(0)
splitPoints.get(0) -> splitPoints.get(1)
...
splitPoints.get(3) -> 100.
Take four numbers from below range:
4 to n-1
And then divide each number by four .
And fifth number to be n - (sum of other four).
Where n is 100 in the given case..
Again this is one way of implementation and there are hundred of ways to implement it
Hope that helps.
The most efficient way to do this and to keep proper distribution - looks like this.
1) In general cases. You need divide line into N parts.
generate N-1 doubles [0,1], add 0 and 1, and sort them -> x[i] = {0, ..., 1}
N-1 point divide line into N parts -> 0=x[0]..x[1]; x[1]...x[2]; ... x[N]..x[N+1]=1
scale each part to proper size -> len[i] = (x[i+1]-x[i])*total_length
cast to int if needed
2) In case when you need large Objects and small gaps - split you length with desirable proportion, like 70% for objects and 30% for gaps. Or generate it nextDouble(0.2)+0.2 for [0.2,0.4) range for gaps. Then use proposed algorithm twice.
I am using NextDouble() to generate uniform random number. I generated random number with 500 different seeds and found that the generated uniform random number is biased towards higher uniform number (mean was 0.93). Which is very absurd. I then divided the seed by 10000 and the random number generated was perfect (mean was 0.51).
I found that the seed should not be more than 48 bits and so made sure that the seed I provide (seed for NextDouble() is generated randomly using nextLong() with seed = 12345) is less 48 bits. Then I re-generated the random number 500 times and found the same problem. Does anyone had similar issues with NextDouble()?
Please see the code below:
Random randObject = new Random();
randObject.setSeed(12345);
long[] seed = new long[501];
for (int i = 1; i<=500; i++)
seed[i] = (long)( ( randObject.nextLong() / (double)Long.MAX_VALUE ) * Math.pow( 2, 48 ) ); // to make sure seed is not more than 48 bits
for (int i = 1; i<=500; i++)
{
randObject.setSeed(seed[i]);
randObject.nextDouble();
}
Thanks
"...I generated [a] random number with 500 different seeds..."
That's your problem. A random number generator generates a sequence of numbers from a given seed, that, taken as a sequence, are random and uniformly distributed. If you only take the first number from the sequence, there are no such guarantees. In fact, an RNG might decide to return the seed itself as its first value--that would be perfectly valid. In practice, they generally hash the seed somehow.
So your 500 numbers are not a random sequence at all. They are simply a hash function of your input seeds, and there's no reason whatsoever to expect them to be random.
The Java-8 version seems to offer a different picture:
public void test() {
Random r1 = new Random();
Random r2 = new Random();
r1.setSeed(12345);
double average = IntStream.range(0, 5000)
// 5000 random longs.
.mapToLong(i -> r1.nextLong())
// Used as seeds to a Random
.mapToDouble(l -> {
r2.setSeed(l);
return r2.nextDouble();
})
// Gather stats.
.summaryStatistics()
// Average,
.getAverage();
System.out.println("Average: " + average);
}
Prints 0.5000... fairly consistently.
Congratulations
I found that the seed should not be more than 48 bits and so made sure that the seed I provide (seed for NextDouble() is generated randomly using nextLong() with seed = 12345) is less 48 bits.
You proved experimentally that java.util.Random is 48bit LCG generator
From its sources
48: * The algorithm is described in <em>The Art of Computer Programming,
49: * Volume 2</em> by Donald Knuth in Section 3.2.1. It is a 48-bit seed,
50: * linear congruential formula.
51: *
link http://developer.classpath.org/doc/java/util/Random-source.html
Java's Random is a linear congruential generator (LCG), which propagates the next state from the current state. You're using the output of an LCG to seed itself, so each of your seeds is going to be related to the outputs produced by the other seeds. From that point on, all bets are off as to the distributional behavior of the results.
Seed your 500 streams from /dev/random, or with the output of an entirely different class of generator such as a feedback shift register or Mersenne twister. Then, if you're still observing bias, write up a journal paper.
For a distributed application project I want to have two instances share the same/know (pseudo-)random numbers.
This can be achieved by using the same seed for the random number generator (RNG). But this only works if both applications use the RNG output in the same order. In my case this is hard or even impossible.
Another way of doing this is would be (psedocode):
rng.setSeed(42);
int[] rndArray;
for(...) {
rndArray[i] = rng.nextInt();
}
Now both applications would have the same array of random numbers and my problem would be solved.
BUT the array would have to be large, very large. This is where the lazy initialization part comes in: How can I write a class that where rndArray.get(i) is always the same random number (depending on the seed) without generating all values between 0 and i-1?
I am using JAVA or C++, but this problem should be solvable in most programming languages.
You can use a formula based on a random seed.
e.g.
public static int generate(long seed, int index) {
Random rand = new Random(seed + index * SOME_PRIME);
return rand.nextInt();
}
This will produce the same value for a given seed and index combination. Don't expect it to be very fast however. Another approach is to use a formula like.
public static int generate(long seed, int index) {
double num = seed * 1123529253211.0 + index * 10123457689.0;
long num2 = Double.doubleToRawLongBits(num);
return (int) ((num2 >> 42) ^ (num2 >> 21) ^ num2);
}
If it's large and sparse you can use a hash table (downside: the numbers you get depend on your access pattern).
Otherwise you could recycle the solution to a problem from the Programming Pearls (search for something like "programming pearls initialize array"), but it wastes memory iirc.
Last solution I can think of, you could use a random generator which can efficiently jump to a specified position - the one at http://mathforum.org/kb/message.jspa?messageID=1519417 is decently fast, but it generates 16 numbers at a time; anything better?
I can create random numbers from a range using
Random rand = new Random();
int num = rand.nextInt(10);
System.out.println("Generated Random Number between 0 to 10 is : " + num);
But if i need the next random number generated to be a part of the range minus the already generated one, will keeping the above statement in a loop will suffice?
Also I need to stop once i exhaust all the number from the range.
For eg,
The code gives me a random number between [0-10],
1st - 4 - range {[0-10]}
2nd - 9 - range {[0-10]-4}
3rd - 8 - range {[0-10]-4,9}
..
..
10th - 10 - range {[0-10]-[0-9]}
Will this function output from [Range]{this is my requirement} or (Range)? Or is there any better alternative solution?
The easiest way would probably be to:
put the numbers (0 to 10) in a list
call Collections.shuffle() on that list
loop over the list
Something like:
List<Integer> numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 10);
Collections.shuffle(numbers);
System.out.println(numbers);
You can even provide a random generator for the shuffling operation if the default doesn't suit you.
I do not think this is possible. Try to remember the numbers you already generatedin a list and use it to generate more random numbersuntil you find one that is not in your list.
I used the following code to generate the random numbers:
long randNo = Math.round(Math.random() * 10000);
I have some situations where i found duplicates. Is it possible that it will generate same numbers?
Yes, it's possible. If you need to generate 10000 distinct random numbers from 0 to 9999. You can generate list of 10000 consecutive numbers and then call Collections.shuffle on it.
With random numbers, all numbers in the range are equally likely. This means if you get a number, the next value is just as likely to appear as it did the first time.
BTW: using round is not a great idea in you example as the numbers 1 to 9999 are equally likely but the numbers 0 and 10000 are half as likely as they only occur on a half rounded down or half rounded up.
A more efficient pattern is to use
Random rand = new Random();
// as needed
int num = rand.nextInt(10000); // will be [0, 10000)
If you need to generate unique numbers you can use Collections.shuffle
List<Integer> nums = new ArrayList<Integer>();
for(int i = 0; i < 10000; i++) nums.add(i);
Collections.shuffle(nums);
This will give you up to 10000 unique numbers in a random order.