Random Number In A Range - java

I have an app I am writing for iOS and Android. On startup I am trying to get a random number between 1 and 6.
iOS (Objective-C):
int random = rand() % (6 - 1) + 1;
Android (Java):
Random random = new Random();
int num = random.nextInt(6)+1;
In both cases they return 3 every time.
From other questions I have read, people are having the same issue because they are looping through randoms and keep reinstantiating the Random object. But I just want one random number, so I am only instantiating it once.
So, how can I get either of these pieces of code to get a number 1-6 instead of just 3?

For the Objective-C part, I can tell you that you have to seed the random, like this:
srand(time(0)); // seed it using the current time
And for the Java part, the new Random() constructor automatically seeds it in the default JVM for desktop applications, but not on Android. On Android, it uses a default seed value.
Random rand = new Random(System.nanoTime());

In Objective-C, you could alternately use the recommended arc4random() function that does not need to be seeded. You would use it like this:
int random = (arc4random() % 5) + 1;
A huge benefit of this function over rand() is that is has twice the range of rand(), thus allowing for "more random" numbers.

The best solution is to use arc4random_uniform if possible, it is available in iOS 4.3 and above. It eliminates bias that is usually introduced by the mod operator.
+ (u_int32_t)randomInRangeLo:(u_int32_t)loBound toHi:(u_int32_t)hiBound {
int32_t range = hiBound - loBound + 1;
return loBound + arc4random_uniform(range);
}
Note that no seeding is necessary and it produces cryptographic quality random numbers.

Not sure about Random on Android, but in other cases, you probably want to seed the Random instance with something reasonably unique, like the system time.
Random r = new Random(System.currentTimeMillis());

I tried the Java part and it works OK for me, but you can try to instantiate Random using time as a seed:
java.util.Date d = new java.util.Date();
Random random = new Random(d.getTime());
int num = random.nextInt(6)+1;
System.out.println(num);

Related

Random Class with seed

long seed = 0;
Random rand = new Random(seed);
int rand100 = 0;
for(int i = 0; i < 100; i++)
rand100 = rand.nextInt();
System.out.println(rand100);
I wrote this code to get 100th random integer value of given seed. I want to know if there is a way to get 100th random integer value of given seed without calling nextInt() 100 times.
I want to know if there is a way to get 100-th random integer value of given seed without calling nextInt() 100 times.
No, there is no way to directly get the 100-th random number of the sequence without first generating the other 99 values. That's simply because of how the generation works in Java, the values depend on their previous values.
If you want to go into details, take a look at the source code. The internal seed changes with every call of the next method, using the previous seed:
nextseed = (oldseed * multiplier + addend) & mask;
So in order to get the seed for the 100-th value, you need to know the seed for the 99-th value, which needs the seed for the 98-th value and so on.
However, you can easily get the 100-th value with a more compact statement like
long seed = ...
int amount = 100;
Random rnd = new Random(seed);
// Generate sequence of 100 random values, discard 99 and get the last
int val = rnd.ints(100).skip(amount - 1).findFirst().orElse(-1);
Keep in mind that this still computes all previous values, as explained. It just discards them.
After you have computed that value for the first time, you could just hardcode it into your program. Let's suppose you have tested it and it yields 123. Then, if the seed does not change, the value will always be 123. So you could just do
int val = 123;
The sequences remain the same through multiple instance of the JVM, so the value will always be valid for this seed. Don't know about release cycles though, I think it's allowed for Random to change its behavior through different versions of Java.
Yes. As long as the seed is constant, then the result of executing this 100 times will yield the same result every time. As such, you can just do
int rand100 = -1331702554;
If I got you correct, you search for some seeded method like
int[] giveMeInts(int amount, long seed);
There exists something very similar, the Stream methods of Random (documentation):
long seed = ...
int amount = 100;
Random rnd = new Random(seed);
IntStream values = rnd.ints(amount);
You could collect the stream values in collections like List<Integer> or an int[] array:
List<Integer> values = rnd.ints(amount).collect(Collectors.toList());
int[] values = rnd.ints(amount).toArray();
The methods will use the seed of the Random object, so if fed with the same seed they will always produce the same sequence of values.

Generating Random Long value in Java

I am trying to generate two 9 digit long random long value in Java using the below code:
for (int i =0;i<2;i++) {
String axisIdStr = Long.toString((long)(System.nanoTime() * (Math.random() * 1000)));
System.out.println("######## axisIdStr "+axisIdStr);
String axId = axisIdStr.substring((axisIdStr.length() -9), axisIdStr.length()) ;
}
But when I run this in windows, i get two different numbers where as when run in mac, I get same two numbers. Why is this happening ?
Can you suggest a better way to generate the long values?
According to your requirement you need to generate 9 digit random numbers. As in the comment suggested you can do it using random.Below I have just given one solution to generate random number between two numbers.
long lowerLimit = 123456712L;
long upperLimit = 234567892L;
Random r = new Random();
long number = lowerLimit+((long)(r.nextDouble()*(upperLimit-lowerLimit)));
You could create an array a[] of int of size 9, and populate with random integers 0-9. Then sum the array up multiplying accordingly.
a[8]*1 + a[7]*10 + a[6]*100 ...
You need to make sure that a[0] only takes digits 1-9 tho...
To get even more random sequence, you Ideally should work on Strings, then you would be able to get 0 on the start position of your random "string", it won't be a number.
Or maybe generate somthing pseudo random and strip last 9 digits out of it.
That's the DIY version of what you could accomplish with what's already out there...
Regards

Guava - how can I generate a random number using Range?

Google's Guava library provides a great class called Range, it has many useful methods like greaterThan(x), open(x,y), etc. I am wondering if there is any way of applying such method to generate a random number within a Range?
I would not suggest using a range for this basic application.
The easiest method to use is the already implemented Random class.
Here is how to use the class:
For getting a random integer of any value:
Random r = new Random();
r.nextInt();
For getting a random integer in a range of min x, max y:
Random r = new Random();
r.nextInt(y - x) + x;
This is the most basic way of getting a random number in a range.
I bet there is a getMin and getMax method in the range class, so use that for x and y.
Also, if you want a random number greater than a min value of x, just do:
Random r = new Random();
Math.abs(r.nextInt().nextInt()) + x;
^The code above generates any positive integer, and the x ensures the min value.
-or-
nextInt(Integer.MAX_VALUE - (x + 1)) + (x + 1)
-as suggested by ColinD
Hope this helps.
-Classic
Like Louis says there's no built-in way to do this, but there are a couple of fairly straightforward options. Note that we have to assume all Range instances are bounded on both sides - you cannot select a random value from an unbounded or non-discrete range (e.g. (-∞..0]).
The easiest to implement solution is to simply convert the Range into a ContiguousSet, from which you can select a random value in linear time. This has the advantage of working for any discrete type, not just Range<Integer>.
public static C random(Range<C> range, DiscreteDomain<C> domain) {
Set<C> set = ContiguousSet.create(range, domain);
int index = random.nextInt(set.size());
return Iterables.get(set, index);
}
Of course constant time would be better, especially for large ranges. Canonicalizing the Range first reduces the number of cases we have to handle, and we can use the f(y-x) + x pattern JClassic suggests.
public static int random(Range<Integer> range) {
checkArgument(range.hasLowerBound() && range.hasUpperBound(),
"Cannot select a random element from unbounded range %s", range);
Range<Integer> canonical = range.canonical(DiscreteDomain.integers());
return random.nextInt(canonical.upperEndpoint() - canonical.lowerEndpoint())
+ canonical.lowerEndpoint();
}
You can extend this easily for Long with Random.nextLong() (but note that Random.nextLong() cannot return all long values, so SecureRandom would be preferable).

Stable mapping of an integer to a random number

I need a stable and fast one way mapping function of an integer to a random number.
By "stable" I mean that the same integer should always map to the same random number.
And by "random number" I actually mean "some number which behaves like random".
e.g.
1 -> 329423
2 -> -12398791234
3 -> -984
4 -> 42342435
...
If I had enough memory (and time) I would ideally use:
for( int i=Integer.MIN_VALUE; i<Integer.MAX_VALUE; i++ ){
map[i]=i;
}
shuffle( map );
I could use some secure hash function like MD5 or SHA but these are to slow for my purposes and I don't need any crypto/security properties.
I only need this in one way. So I will never have to translate the random number back to its integer.
Background: (For those who want to know more)
I'm planing to use this to invalidate a complete cache over a given amount of time. The invalidation is done "randomly" on access of the cache member with an increasing chance while time passes. I need this to be stable so that isValid( entry ) does not "flicker" and for consistent testing.
The input to this function will be the java hash of the key of the entry which typically is in the range of "1000"-"15000" (but can contain some other stuff, too) and comes in bulks.
The invalidation is done on the condition of:
elapsedTime / timeout * Integer.MAX_VALUE > abs( random( key.hashCode() ) )
EDIT: (this is to long for a comment so I put it here)
I tried gexicide's answer and it turns out this isn't random enough. Here is what I tried:
for( int i=0; i<12000; i++ ){
int hash = (""+i).hashCode();
Random rng = new Random( hash );
int random = rng.nextInt();
System.out.printf( "%05d, %08x, %08x\n", i, hash, random );
}
The output starts with:
00000, 00000030, bac2c591
00001, 00000031, babce6a4
00002, 00000032, bace836b
00003, 00000033, bac8a47e
00004, 00000034, baab49de
00005, 00000035, baa56af1
00006, 00000036, bab707b7
00007, 00000037, bab128ca
00008, 00000038, ba93ce2a
00009, 00000039, ba8def3d
00010, 0000061f, 98048199
and it goes on in this way.
I could use SecureRandom instead:
for( int i=0; i<12000; i++ ){
SecureRandom rng = new SecureRandom( (""+i).getBytes() );
int random = rng.nextInt();
System.out.printf( "%05d, %08x\n", i, random );
}
which indeed looks pretty random but this is not stable anymore and 10 times slower than the method above.
Although you never specified it as a requirement you'll probably want a full 1:1 mapping. This is because the number of possible input values is small. Any output that can occur for more than one input implies another output which can never happen at all. If you have output values which are impossible then you have a skewed distribution.
Of course, if your input is skewed then your output will be skewed anyway, and there's not much you can do about that.
Anyway; this makes it a unique int to int hash.
Simply apply a couple of trivial, independent 1:1 mapping functions until things are suitably distributed. You've already isolated one transform from the Random class, but I suggest mixing it with some other transforms like shifts and XORs to avoid individual weaknesses of different algorithms.
For example:
public static int mapInteger( int value ){
value *= 1664525;
value += 1013904223;
value ^= value >>> 12;
value ^= value << 25;
value ^= value >>> 27;
value *= 1103515245;
value += 12345;
return value;
}
If that's good enough then you can make it faster by deleting lines at random (I suggest you keep at least one multiply) until it's not good enough anymore, and then add the last deleted line back in.
Use a Random and seed it with your number:
Random generator = new Random(i);
return generator.nextInt();
As your testing exposes, the problem with this method is that such a seed creates a very poor random number in the first iteration. To increase the quality of the result, we need to run the random generator a few times; this will fill up the state of the random generator with pseudo-random values and will increase the quality of the following values.
To make sure that the random generator spreads the values enough, use it a few times before outputting the number. This should make the resulting number more pseudo-random:
Random generator = new Random(i);
for(int i = 0; i < 5; i++) generator.nextInt();
return generator.nextInt();
Try different values, maybe 5 is enough.
The answer of gexicide is the correct (and the most simple) one. Just one note:
Running this 1,000,000 times on my system takes about 70ms. (Which is pretty fast.)
But it involves at least two object creations and feeds the GC. It would be better
if this could be done on the stack and not using object creation at all.
Looking at the sources of Random class it shows that there is some code to make
it callable multiple times and to make it threadsafe which can be removed.
So I ended up with a reimplementation in one method:
public static int mapInteger( int value ){
// initial scramble
long seed = (value ^ multiplier) & mask;
// shuffle three times. This is like calling rng.nextInt() 3 times
seed = (seed * multiplier + addend) & mask;
seed = (seed * multiplier + addend) & mask;
seed = (seed * multiplier + addend) & mask;
// fit size
return (int)(seed >>> 16);
}
(multiplier, addend and mask are some constants used by Random)
Running this 1,000,000 times gives the same result but takes only 5ms and is therefor 10 times faster.
BTW: This happens to be another piece of code from The Old Man - again. See Donald Knuth,
The Art of Computer Programming, Volume 2, Section 3.2.1

Selecting a random color in java

I have an iPhone version of my application which is using a bit of code for setting up colors.
((rand() % 176) * 80) / 256.0f
I am new to objective c so I can't figure out how this is working. I want to make exact copy of this for Android in Java.
In Java we usually use Random() . How am i suppose to implement this above function using Random r = Random();
In Android, I'd first initialize a variable rand = new Random(). Then I would write your expression as:
rand.nextInt(176) / 3.2f
(Note that 80 / 256.0 == 1 / 3.2.) I would only assign a value to rand once and reuse the same Random object each time I needed a new color.
After a little back-of-the-envelope work, it seems that your original code is just a fancy way of computing a random float value uniformly distributed between 0 and 55.0f. Thus, a much simpler way of doing the same thing would be:
rand.nextFloat(55)
The only disadvantage of this is that it doesn't resemble the original code very closely (although it will behave the same).
Equivalent one-liner in Java would be:
((new Random().nextInt() % 176) * 80) / 256.0f;
More about the random class on the JavaDoc
Obviously you should not create a new instance of Random each time.
Random r = new Random();
// call r.nextInt() each time you need a new random integer
double color = ((r.nextInt() % 176) * 80) / 256.0f;

Categories

Resources