I would like to generate random identifier in java. The identifier should have a fixed size, and the probability of generating the same identifier twice should be very low(The system has about 500 000 users).In addition; the identifier should be so long that it’s unfeasible to “guess it” by a brute force attack.
My approach so far is something along the lines of this:
String alphabet = "0123456789ABCDE....and so on";
int lengthOfAlphabet = 42;
long length = 12;
public String generateIdentifier(){
String identifier = "";
Random random = new Random();
for(int i = 0;i<length;i++){
identifier+= alphabet.charAt(random.nextInt(lengthOfAlphabet));
}
return identifier;
}
I’m enforcing the uniqueness by a constraint in the database. If I hit an identifier that already has been created, I’ll keep generating until I find one that’s not in use.
My assumption is that I can tweak lenghtOfAlpahbet and length to get the properties I’m looking for:
Rare collisions
Unfeasible to brute force
The identifier should be as short as possible, as the users of the system will have to type it.
Is this a good approach? Does anyone have any thoughts on the value of “length”?
I think randomUUID is your friend. It is fixed width. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/UUID.html#randomUUID()
If I remember my math correctly, since the UUID is 32 hex numbers (0-f) then the number of permutations are 16^32, which is a big number, and therefore pretty hard to guess.
I would suggest keeping it simple, and use built in methods to represent normal pseudo-random integers encoded as Strings:
Random random = new Random();
/**
* Generates random Strings of 1 to 6 characters. 0 to zik0zj
*/
public String generateShortIdentifier() {
int number;
while((number=random.nextInt())<0);
return Integer.toString(number, Character.MAX_RADIX);
}
/**
* Generates random Strings of 1 to 13 characters. 0 to 1y2p0ij32e8e7
*/
public String generateLongIdentifier() {
long number;
while((number=random.nextLong())<0);
return Long.toString(number, Character.MAX_RADIX);
}
Character.MAX_RADIX is 36, which would equal an alphabet of all 0 to 9 and A to Z. In short, you would be converting the random integers to a number of base 36.
If you want, you can tweak the length you want, but in just 13 characters you can encode 2^63 numbers.
EDIT: Modified it to generate only 0 to 2^63, no negative numbers, but that's up to you.
Related
I have to generate unique serial numbers for users consisting of 12 to 13 digits. I want to use random number generator in Java giving the system. Time in milliseconds as a seed to it. Please let me know about the best practice for doing so. What I did was like this
Random serialNo = new Random(System.currentTimeMillis());
System.out.println("serial number is "+serialNo);
Output came out as: serial number is java.util.Random#13d8cc98
For a bit better algorithm pick SecureRandom.
You passed a seed to the random constructor. This will pick a fixed sequence with that number. A hacker knowing the approximate time of calling, might restrict the number of attempts. So another measure is not using the constructor and nextLong at the same spot.
SecureRandom random = new SecureRandom();
long n = random.nextLong();
A symmetric bit operation might help:
n ^= System.currentMillis();
However there is a unique number generation, the UUID, a unique 128 bits number, two longs. If you xor them (^) the number no longer is that unique, but might still be better having mentioned the circumstantial usage of random numbers.
UUID id = UUID.randomUUID();
long n = id.getLeastSignificantBits() ^ id.getMostSignificantBits();
Create a random number generator using the current time as seed (as you did)
long seed = System.currentTimeMillis();
Random rng = new Random(seed);
Now, to get a number, you have to use the generator, rng is NOT a number.
long number = rng.nextLong();
According to the documentation, this will give you a pseudorandom number with 281.474.976.710.656 different possible values.
Now, to get a number with a maximum of 13 digits:
long number = rng.nextLong() % 10000000000000;
And to get a number with exactly 13 digits:
long number = (rng.nextLong() % 9000000000000) + 1000000000000;
First, import the Random class:
import java.util.Random;
Then create an instance of this class, with the current milliseconds as its seed:
Random rng = new Random(System.currentTimeMillis());
This line would generate an integer that can have up to 13 digits:
long result = rng.nextLong() % 10000000000000;
This line would generate an integer that always have 13 digits:
long result = rng.nextLong() % 9000000000000 + 1000000000000;
There are three ways to generate Random numbers in java
java.util.Random class
We can generate random numbers of types integers, float, double, long, booleans using this class.
Example :
//Random rand = new Random();
// rand_int1 = rand.nextInt(1000)
Math.random method : Can Generate Random Numbers of double type.
random(), this method returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Example :
Math.random());
//Gives output 0.15089348615777683
ThreadLocalRandom class
This class is introduced in java 1.7 to generate random numbers of type integers, doubles, booleans etc
Example :
//int random_int1 = ThreadLocalRandom.current().nextInt();
// Print random integers
//System.out.println("Random Integers: " + random_int1);
I have a logic to generate unique ID in java as below,
private static String generateUniqueNum()
{
final int LENGTH = 20;
final long uniqueNumber = abs(Long.valueOf(UUID.randomUUID().hashCode())) + System.currentTimeMillis() + abs(random.nextLong());
String value = Long.toString(uniqueNumber).replaceAll("-", "");
final int endIndex = value.length() <= LENGTH ? value.length() : LENGTH;
return String.format("MN%s", value.substring(0, endIndex));
}
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
For the above code I have tested with jmeter with 3000 requests simultaneously and when I checked the result value generted, there are lot of duplicate valus generated. I dont know the reason how the duplicate value generated. Can someone has any idea on this.
Thanks in advance.
UUID is unique but uses 128 bits (two longs).
It would be best to use for a database key for instance the String representation. For a less safe long:
return uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits();
Your clashes stem from hash code being an int (32 bits, a quarter), and combining with other properties will not necessarily make the number more random; even less so.
There are few problems with your current approach:
java.util.Random is not thread-safe. If you have 3000 concurrent requests on different threads to the same Random object you may get strange behavior. Try ThreadLocalRandom instead.
Generated System.currentTimeMillis() values will be close together if the 3000 concurrent requests are simultaneous.
Don't over complicate the problem, if you need a unique identifier:
Use UUID v4 (UUID.randomUUID()) or if you need stronger guarantees UUID v1. There is enough random bits in the UUID to guarantee that collisions are extremely unlikely.
If you need something more concise maintain a shared counter e.g. database sequence. Simply increment by one each time you want new unique number.
Q: Why is your scheme giving significant non-uniqueness?
A: There is a howler of bug!
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
If number is less than zero, the 0 < number means that this abs method will returning zero as the "absolute" value.
Why does that matter? Well, your random number generation effectively does this:
long number = yourAbs(random int) + current time in millis + yourAbs(random long)
But because of your bug, there is a 50% probability that first term will be zero and a 50% probability that the last term will be zero.
So there is a 25% probablility, your "random" number will be the current time in milliseconds! Now suppose that you call generateUniqueNum() twice in a millisecond .....
Oooops!!!
Note that without this bug, your code would still have a chance of 1 in 264 that any pair of numbers generated will be equal. If you then combine this with a "birthday paradox" analysis, the probability of any collisions becomes significant.
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 am randomly generating numbers using java.util.Random. But, I can not keep the length of the numbers fixed. Can you help me please?
To fix the length of a randomly generated number, generally you'll want to fix the random number generation to a range. For instance, if you'd like to generate a 6 digit long random number, you'll want numbers from 100,000 to 999,999. You can achieve this by using the following formula.
Random r = new Random();
int randomNum = r.nextInt((max - min) + 1) + min;
Where max is the maximum number, such as 999999, and min is your minimum number, such as 100000.
EDIT:
Based on your comment, I see that you're trying to generate a 15-digit number containing only 1-5 inclusive. Here is a simple way to do this:
import java.util.Random;
StringBuilder s = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 15; i++) {
s.append(r.nextInt(5) + 1);
}
System.out.println("The random number is: " + s.toString());
As noted by #MichaelT, a 15 digit number will not fit in an integer. If you need to perform an operation on it, you should store it in a long.
long randomLong = Long.valueOf(s.toString()).longValue();
Rather than thinking of generating an integer, think in terms of generating a String of 15 digits, each in the required range.
You can use nextInt(int) to pick each digit.
The first thing to consider is that an int cannot hold 15 digits. It just can't. It can only go up to 232 -1, which is 9 digits long. A long can hold up to 19 digits - but if one wants to solve for the general case, it is necessary to use the BigInteger package instead.
Remember that BigInteger is an immutable object (like String) and thus you must assign the value back when looping.
package com.michaelt.so.random15;
import java.math.BigInteger;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
BigInteger result = BigInteger.ZERO;
for(int i = 0; i < 15; i++) {
result = result.multiply(BigInteger.TEN)
.add(BigInteger.valueOf(r.nextInt(5)+1));
}
System.out.println(result.toString());
}
}
It starts out with the value ZERO, and loops through for 15 times, each time first multiplying the value by 10 (another BigInteger preallocated value) and then adds the new value into the 1's position. It does this 15 times.
When done, one can get its value as a string or long or other format - or continue to use it as a BigDecimal (necessary if you should ever decide you want a 20 digit long value).
Runs of the above code produce output such as:
313455131111333
245114532433152
531153533113523
If you're ok using libraries:
RandomStringUtils.random(15, "12345")
would give you Strings like: 124444211351355 of length 15
I just happened to write a post about that (shameless self-advertising link: http://united-coders.com/nico-heid/generating-random-numbers-strings-java/)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java random number with given length
I have been trying to generate a 15 digit long number in java but it seems I have failed to do it so far as using:
This is producing a maximum of 10 digits.
Random random = new Random();
int rand15Digt = random.nextInt(15);
How can I generate it successfully?
Use Random's method public long nextLong()
To begin with, an int can hold numbers between -2,147,483,648 and 2,147,483,647.
Use Random.nextLong()
Any number can be formatted into 15 decimal digits when presented as a string. This is achieved when the number is converted to a String, e.g.:
System.out.println(String.format("%015d", 1));
// prints: 000000000000001
If you want to generate a random number that lies between 100,000,000,000,000 and 999,999,999,999,999 then you can perform a trick such as:
Random random = new Random();
long n = (long) (100000000000000L + random.nextFloat() * 900000000000000L);
If your ultimate goal is to have a 15-character string containing random decimal digits, and you're happy with third-party libraries, consider Apache commons RandomStringUtils:
boolean useLetters = false;
boolean useNumbers = true;
int stringLength = 15;
String result = RandomStringUtils.random(stringLength, useLetters, useNumbers)
What about trying BigInteger, see this StackOverflow link for more information Random BigInteger Generation
In Hibernate have UUIDGenerator class using this we can create Secure Random and Unique Number also.
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
String uuid = (String)super.generate(session, object);
return uuid.substring(uuid.length()-15, uuid.length());
}
i think this is best way to Generate Unique and also Random Number...