Random number generator without duplication - java

I am trying to have a piece of code in which a random number would be generated and will be saved in a collection so next time when another random number is generated i can check if this new number is already in list or not.
The main point of this method would be generating a number in ranged of 1 to 118, no duplicated number allowed.
Random rand = new Random();
randomNum2 = rand.nextInt(118) + 1;
if (!generated.contains(randomNum2))
{
String strTemp = "whiteElements\\"+String.valueOf(randomNum2)+".JPG";
btnPuzzlePiece2.setIcon(new ImageIcon(strTemp));
generated.add(randomNum2);
btnPuzzlePiece2.repaint();
}
else
setPicForBtnGame1();
BUT the problem is in this piece of code as the program continues generating numbers the possibility to have a correct random number (in range without duplicating) imagine after running the method 110 times... the possibility for the method to generate a valid random number reduces to less than 1%... which leaves the program with the chance of never having the list of numbers from 1-118 and also too much waste of process.
so how can i write this correctly?
p.s i thought of making 118 object and save them in a collection then generate a random object and after remove the object from the list so the next element has no chance of being duplicated.
Help me out please ...

Create a List, and populate it with the elements in your range. Then shuffle() the list, and the order is your random numbers. That is, the 0-th element is your first random number, the 1st element is your second random number, etc.

Wouldn't it be better to just generate something that can never be a duplicate?
A random number with no duplicates is usually known as a UUID.
The easiest way to generate a UUID is to prefix your random number with the current system time in milliseconds.
Of course there's a chance that it could be a duplicate but it's vanishingly small. Of course it might be long, so you'd want to then base64 encode it for example, to reduce it's size.
You can get a more or less guaranteed UUID down to about 8 characters using encoding.

Related

Huge sorted list of random numbers

I need to create a method which returns a number sampled of some random distribution where every time call the method the returned number is bigger than any previously returned numbers.
Or, in other words, i need an iterator for a sorted list of random values.
Unfortunately the list is too big to be created in memory as a whole. The first idea i came up with is to divide my value space into buckets, where each bucket contains values in some range [a, b).
Say my list has N elements. To create a bucket i would sample my distribution N times and put each value in the range [a, b) into the bucket. Values outside that bucket would be discarded.
This way i could create a new bucket each time i iterated over the last and keep memory consumption low.
Yet, as i am not an expert in statistics, i am a little afraid this will somehow screw up the numbers i get. Is this an appropriate approach? Is it important to use the same exact distribution generator (an instance of org.apache.commons.math3.distribution.RealDistribution) for each bucket?
Update: It seems i did a bad job of explaining what kind of random number i am talking about.
My numbers form a sample of a random distribution like for example a normal distribution with a mean of m and variance of v, or an uniform distribution or exponential distribution.
I use those numbers to model some behavior in a simulation. Say i want to trigger events at some times. I need to schedule billions of events and the times those events are triggered must form a sample of a random distribution.
So if i derive my next number by adding a random number to my previous number i indeed get a sequence of growing random numbers but the numbers wont form a sample of my distribution.
On you can say what are the requirements of your random generator.
I need to create a method which returns a number sampled of some random distribution where every time call the method the returned number is bigger than any previously returned numbers.
You can do something like.
private long previous = 0;
private final Random rand = new Random();
public long nextNumber() {
return previous += rand.nextInt(10) + 1;
}
The details depend on how you want to model your random numbers.
If the list is too big to store in memory, you can use a database and read/write batches of list items to and from the database.
This way you only ever need to store one batch in memory at any one time.
I would start off by creating a variable and storing your first random number, then generate another random number, compare them and if it is larger save it in both large storage and ram, repeat as the next random number would be compared to single value in memory.
You could add a random number to the previously generated number. So you have to keep in memory only the number you generated in the iteration step before.
SamplePartitioner is a class which divides a sample of some distribution in several partitions of fixed size, which are returned, one by one, by nextPartition().
nextPartition() creates the whole sample on every call but stores only the smallest partitionSize values, which are bigger than the biggest value of the last partition. By using a fixed seed, nextPartition() creates the exact same sample each time it is called.
class SamplePartitioner(sampleSize: Long, partitionSize: Int, dist: RealDistribution) {
private val seed = Random.nextInt
private var remaining = sampleSize
private var lastMax = 0.0
def nextPartition(): SortedSet[Double] = remaining.min(partitionSize) match {
case 0 => SortedSet.empty[Double]
case targetSize =>
dist.reseedRandomGenerator(seed)
val partition = fill(sampleSize, SortedSet.empty, targetSize)
lastMax = partition.last
remaining -= partition.size
partition
}
private def fill(samples: Long, partition: SortedSet[Double], targetSize: Long): SortedSet[Double] =
samples match {
case 0 => partition
case n =>
val sample = dist.sample()
val tmp = if (sample > lastMax) partition + sample else partition
fill(n - 1, if (partition.size > targetSize) tmp.init else tmp, targetSize)
}
}

How to be sure that random numbers are unique and not duplicated?

I have a simple code which generates random numbers
SecureRandom random = new SecureRandom();
...
public int getRandomNumber(int maxValue) {
return random.nextInt(maxValue);
}
The method above is called about 10 times (not in a loop). I want to ensure that all the numbers are unique (assuming that maxValue > 1000).
Can I be sure that I will get unique numbers every time I call it? If not, how can I fix it?
EDIT: I may have said it vaguely. I wanted to avoid manual checks if I really got unique numbers so I was wondering if there is a better solution.
There are different ways of achieving this and which is more appropriate will depend on how many numbers you need to pick from how many.
If you are selecting a small number of random numbers from a large range of potential numbers, then you're probably best just storing previously chosen numbers in a set and "manually" checking for duplicates. Most of the time, you won't actually get a duplicate and the test will have practically zero cost in practical terms. It might sound inelegant, but it's not actually as bad as it sounds.
Some underlying random number generation algorithms don't produce duplicates at their "raw" level. So for example, an algorithm called a XORShift generator can effectively produce all of the numbers within a certain range, shuffled without duplicates. So you basically choose a random starting point in the sequence then just generate the next n numbers and you know there won't be duplicates. But you can't arbitrarily choose "max" in this case: it has to be the natural maximum of the generator in question.
If the range of possible numbers is small-ish but the number of numbers you need to pick is within a couple of orders of magnitude of that range, then you could treat this as a random selection problem. For example, to choose 100,000 numbers within the range 10,000,000 without duplicates, I can do this:
Let m be the number of random numbers I've chosen so far
For i = 1 to 10,000,000
Generate a random (floating point) number, r, in the range 0-1
If (r < (100,000-m)/(10,000,000-i)), then add i to the list and increment m
Shuffle the list, then pick numbers sequentially from the list as required
But obviously, there's only much point in choosing the latter option if you need to pick some reasonably large proportion of the overall range of numbers. For choosing 10 numbers in the range 1 to a billion, you would be generating a billion random numbers when by just checking for duplicates as you go, you'd be very unlikely to actually get a duplicate and would only have ended up generating 10 random numbers.
A random sequence does not mean that all values are unique. The sequence 1,1,1,1 is exactly as likely as the sequence 712,4,22,424.
In other words, if you want to be guaranteed a sequence of unique numbers, generate 10 of them at once, check for the uniqueness condition of your choice and store them, then pick a number from that list instead of generating a random number in your 10 places.
Every time you call Random#nextInt(int) you will get
a pseudorandom, uniformly distributed int value between 0 (inclusive)
and the specified value (exclusive).
If you want x unique numbers, keep getting new numbers until you have that many, then select your "random" number from that list. However, since you are filtering the numbers generated, they won't truly be random anymore.
For such a small number of possible values, a trivial implementation would be to put your 1000 integers in a list, and have a loop which, at each iteration, generates a random number between 0 and list.size(), pick the number stored at this index, and remove it from the list.
This is code is very efficient with the CPU at the cost of memory. Each potiental value cost sizeof(int) * maxValue. An unsigned integer will work up to 65535 as a max. long can be used at the cost of a lot of memory 2000 bytes for 1000 values of 16 bit integers.
The whole purpose of the array is to say have you used this value before or not 1 = yes
'anything else = no
'The while loop will keep generating random numbers until a unique value is found.
'after a good random value is found it marks it as used and then returns it.
'Be careful of the scope of variable a as if it goes out of scope your array could erased.
' I have used this in c and it works.
' may take a bit of brushing up to get it working in Java.
unsigned int a(1000);
public int getRandomNumber(int maxValue) {
unsigned int rand;
while(a(rand)==1) {
rand=random.nextInt(maxValue);
if (a(rand)!=1) { a(rand)=1; return rand;}
}
}

Why this code is giving strange result? So Random?

I have piece of code which generates some Random number and prints out on console. However I am curious about the pattern which it prints, Such as,
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Random random = new Random(-6732303926L);
for(int i=0;i<10;i++)
System.out.println(random.nextInt(10)+" ");
}
}
Result : 0 1 2 3 4 5 6 7 8 9 - Every number in new line.
And if you change this code a bit! like,
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Random random = new Random(-6732303926L);
for(int i=0;i<10;i++)
System.out.println(random.nextInt(11)+" ");
}
}
Result : 8 9 2 2 10 3 8 7 0 10 - Every number in new line.
What is the reason of 0123456789 which is not random at all!?
0123456789 is random too, in this case - it's about as likely to come up as 14235682907, which would no doubt not have given you any cause for concern.
You spotted a fluke, basically. If you print the next 10 numbers in the first case, they're not preserving any obvious order.
It's like flipping a coin - the pattern HHHHHHHH is just as likely to come up as the exact pattern HHTHTTHH; there's a 1 in 28 chance of each coming up, as at any of the 8 steps there's a 50% chance of it going wrong. But the first pattern looks like it's broken, whereas the second doesn't.
I think it is random... you are using a specific seed for the random function. You just found the seed that will give you the numbers 0 - 9, in order.
EDIT: Apparently, this is the algorithm:
The java.util.Random class implements what is generally called a linear congruential generator (LCG). An LCG is essentially a formula of the following form:
numberi+1 = (a * numberi + c) mod m
Source: here
The Random class is a pseudo-random number generator. Thus it is not truely random, but instead relies on mathematical operations performed on an initial seed value. Thus, certain seeds will produce certain (potentially interesting/fun) sequences
The reason for the sequence is so that one can test software by making Random predicable with predictable and repeatable sequences using its next methods. Whenever a particular long seed parameter is a parameter to the Random constructor, the instanced Random object is supposed to return the same sequences of values through its next methods. This is a deliberate feature of java.util.Random.
java.util.Random has two constructors:
Random()
and
Random(long seed)
The constructor without a long integer seed uses the system time for creating a seed value for the pseudo random number generator. No two instantiations of Random will use the same seed and you should get a very good pseudo-random sequence. A Random instantiation using the constructor without a seed creates an instance with unpredictable sequences of values that will be pseudo-random.
The constructor with a seed value is intended only for making Random deterministic with predictable sequences using its next methods. The typical use of a seed is for software test purposes where results must be predicable and repeatable. Every instance of Random that uses the same long seed integer will create the same sequence of results every time. The particular long you used causes the sequence to be 0 1 2 3 4 5 6 7 8 9 over and over again when getting one of 10 integer values using nextInt(10) method. This and other predictable sequences that are repeatable every time software executes are very useful for testing software and are not meant for creating unpredictable pseudo-random sequences.
Creating random with a seed ensures a certain behavior. Especially, creating two instances of Random with the same seed, will always behave identically. Someone found out (via brute force, I guess) that using this particular seed together with the first 10 nextInt(10), creates such a seemingly ordered sequence. This sequence is pseudo-random updon first creation, but can be reproduced. Changing anything in the slightest gives a different result.
Random is based on the seed you give to it, if you want to get true random numbers, use time functions as seeds, and you'll get a real random number series.

Generate random integers in java

How to generate random integers but making sure that they don't ever repeat?
For now I use :
Random randomGenerator = new Random();
randomGenerator.nextInt(100);
EDIT I
I'm looking for most efficient way, or least bad
EDIT II
Range is not important
ArrayList<Integer> list = new ArrayList<Integer>(100);
for(int i = 0; i < 100; i++)
{
list.add(i);
}
Collections.shuffle(list);
Now, list contains the numbers 0 through 99, but in a random order.
If what you want is a pseudo-random non-repeating sequence of numbers then you should look at a linear feedback shift register. It will produce all the numbers between 0 and a given power of 2 without ever repeating. You can easily limit it to N by picking the nearest larger power of 2 and discarding all results over N. It doesn't have the memory constraints the other colleciton based solutions here have.
You can find java implementations here
How to generate random integers but making sure that they don't ever repeat?
First, I'd just like to point out that the constraint that the numbers don't repeat makes them non-random by definition.
I think that what you really need is a randomly generated permutation of the numbers in some range; e.g. 0 to 99. Even then, once you have used all numbers in the range, a repeat is unavoidable.
Obviously, you can increase the size of your range so that you can get a larger number without any repeats. But when you do this you run into the problem that your generator needs to remember all previously generated numbers. For large N that takes a lot of memory.
The alternative to remembering lots of numbers is to use a pseudo-random number generator with a long cycle length, and return the entire state of the generator as the "random" number. That guarantees no repeated numbers ... until the generator cycles.
(This answer is probably way beyond what the OP is interested in ... but someone might find it useful.)
If you have a very large range of integers (>>100), then you could put the generated integers into a hash table. When generating new random numbers, keep generating until you get a number which isn't in your hash table.
Depending on the application, you could also generate a strictly increasing sequence, i.e. start with a seed and add a random number within a range to it, then re-use that result as the seed for the next number. You can set how guessable it is by adjusting the range, balancing this with how many numbers you will need (if you made incremental steps of up to e.g., 1,000, you're not going to exhaust a 64-bit unsigned integer very quickly, for example).
Of course, this is pretty bad if you're trying to create some kind of unguessable number in the cryptographic sense, however having a non-repeating sequence would probably provide a reasonably effective attack on any cypher based on it, so I'm hoping you're not employing this in any kind of security context.
That said, this solution is not prone to timing attacks, which some of the others suggested are.
Matthew Flaschen has the solution that will work for small numbers. If your range is really big, it could be better to keep track of used numbers using some sort of Set:
Set usedNumbers = new HashSet();
Random randomGenerator = new Random();
int currentNumber;
while(IStillWantMoreNumbers) {
do {
currentNumber = randomGenerator.nextInt(100000);
} while (usedNumbers.contains(currentNumber));
}
You'll have to be careful with this though, because as the proportion of "used" numbers increases, the amount of time this function takes will increase exponentially. It's really only a good idea if your range is much larger than the amount of numbers you need to generate.
Since I can't comment on the earlier answers above due to not having enough reputation (which seems backwards... shouldn't I be able to comment on others' answers, but not provide my own answers?... anyway...), I'd like to mention that there is a major flaw with relying on Collections.shuffle() which has little to do with the memory constraints of your collection:
Collections.shuffle() uses a Random object, which in Java uses a 48-bit seed. This means there are 281,474,976,710,656 possible seed values. That seems like a lot. But consider if you want to use this method to shuffle a 52-card deck. A 52-card deck has 52! (over 8*10^67 possible configurations). Since you'll always get the same shuffled results if you use the same seed, you can see that the possible configurations of a 52-card deck that Collections.shuffle() can produce is but a small fraction of all the possible configurations.
In fact, Collections.shuffle() is not a good solution for shuffling any collection over 16 elements. A 17-element collection has 17! or 355,687,428,096,000 configurations, meaning 74,212,451,385,344 configurations will never be the outcome of Collections.shuffle() for a 17-element list.
Depending on your needs, this can be extremely important. Poor choice of shuffle/randomization techniques can leave your software vulnerable to attack. For instance, if you used Collections.shuffle() or a similar algorithm to implement a commercial poker server, your shuffling would be biased and a savvy computer-assisted player could use that knowledge to their benefit, as it skews the odds.
If you want 256 random numbers between 0 and 255, generate one random byte, then XOR a counter with it.
byte randomSeed = rng.nextInt(255);
for (int i = 0; i < 256; i++) {
byte randomResult = randomSeed ^ (byte) i;
<< Do something with randomResult >>
}
Works for any power of 2.
If the Range of values is not finite, then you can create an object which uses a List to keep track of the Ranges of used Integers. Each time a new random integer is needed, one would be generated and checked against the used ranges. If the integer is unused, then it would add that integer as a new used Range, add it to an existing used Range, or merge two Ranges as appropriate.
But you probably really want Matthew Flaschen's solution.
Linear Congruential Generator can be used to generate a cycle with different random numbers (full cycle).

How to generate a random number with Java from given list of numbers

Assume I have an array/vector of numbers like 1,3,7,9 then I need to guess a number from this list randomly. Using Random class in Java it seems like not possible to do this. Could anyone kindly help me to tell a way to do this kind of thing. I have to change the list of numbers used to generate random number. I am trying to implement a strategy to play battleship game automatically as an assignment. Kindly help me to do this ?
If you just want to select one random number only, or want to select multiple random numbers with reinsertion (i.e. allow possibility of selecting the same number multiple times), you can generate a random index:
List<Integer> lst = ....;
int index = new Random().nextInt(lst.size());
Integer randomeValue = lst.get(index);
You can use an array instead as well. This requires O(1) for each selection.
If you need to select multiple distinct random numbers from the list, then using Collections.shuffle() and iterating through the list would be a better solution. This requires O(n) for all the queries.
Put the numbers in an ArrayList and use Collections.shuffle(arrayList);
I'm with tordek on this one: Doesn't shuffling seem like a fairly heavy-weight way to select a configured number of random numbers from a source vector?
Wouldn't it be faster to just take msaeed's suggestion for how to pick one random number, and repeat it n times? Perhaps assemble your random values as a Set, and keep selecting until your set size is big enough... (don't forget some kind of a check for the edge condition where there's insufficient numbers in the source vector to supply the configured number of random values)

Categories