Random number array with lazy initialization - java

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?

Related

Using an array of precomputed powers to extract roots

I am writing a program that solves a sum of tenth powers problem and I need to have a fast algorithm to find n^10 as well as n^(1/10) For natural n<1 000 000. I am precomputing an array of powers, so n^10 (array lookup) takes O(1). For n^(1/10) I am doing a binary search. Is there any way to accelerate extraction of a root beyond that? For example, making an array and filling elements with corresponding roots if the index is a perfect power or leaving zero otherwise would give O(1), but I will run out of memory. Is there a way to make root extraction faster than O(log(n))?
Why should the array of roots run out of memory? If it is the same size as the array of powers, it will fit using the same datatypes. However for the powers, (10^6)^10 = 10^60, which does not fit into a long variable so you need to use biginteger or bigdecimal types. In case your number n is bigger than the biggest array size n_max your memory can afford, you can divide n by n_m until it fits, i.e. split n = n_max^m*k, where m is a natural number and k < n_max:
public class Roots
{
static final int N_MAX = 1_000_000;
double[] roots = new double[N_MAX+1];
Roots() {for (int i = 0; i <= N_MAX; i++) {roots[i] = Math.pow(i, 0.1);}}
double root(long n)
{
int m = 0;
while (n > N_MAX)
{
n /= N_MAX;
m++;
}
return (Math.pow(roots[N_MAX],m)*roots[(int)n]); // in a real case you would precompute pow(roots[N_MAX],m) as well
}
static public void main(String[] args)
{
Roots root = new Roots();
System.out.println(root.root(1000));
System.out.println(root.root(100_000_000_000_000l));
}
}
Apart LUT You got two options to speed up I can think of:
use binary search without multiplication
If you are using bignums then 10th-root binary search search is not O(log(n)) anymore as the basic operation used in it are no longer O(1) !!! For example +,-,<<,>>,|,&,^,>=,<=,>,<,==,!= will became O(b) and * will be O(b^2) or O(b.log(b)) where b=log(n) depending on algorithm used (or even operand magnitude). So naive binary search for root finding will be in the better case O(log^2(n).log(log(n)))
To speedup it you can try not to use multiplication. Yes it is possible and the final complexity will bee O(log^2(n)) Take a look at:
How to get a square root for 32 bit input in one clock cycle only?
To see how to achieve this. The difference is only in solving different equations:
x1 = x0+m
x1^10 = f(x0,m)
If you obtain algebraically x1=f(x0,m) then each multiplication inside translate to bit-shifts and adds... For example 10*x = x<<1 + x<<3. The LUT table is not necessary as you can iterate it during binary search.
I imagine that f(x0,m) will contain lesser powers of x0 so analogically compute all the needed powers too ... so the final result will have no powering. Sorry too lazy to do that for you, you can use some math app for that like Derive for Windows
you can use pow(x,y) = x^y = exp2(y*log2(x))
So x^0.1 = exp2(log2(x)/10) But you would need bigdecimals for this (or fixed point) here see how I do it:
How can I write a power function myself?
For more ideas see this:
Power by squaring for negative exponents

Pick a number randomly from two numbers

I have two integers, let them be
int a = 35:
int b = 70;
I want to pick one of them randomly at runtime and assign to another variable. I.e.
int c = a or b:
One of the ways that come into my mind is to create an array with these two integers and find a random integer between 0 and 1 and use it as the index of the array to get the number..
Or randomize boolean and use it in if-else.
My question is that is there a better and more efficient way to achieve this? I.e. pick a number from two previously defined integers?
Is there a specific reason you are asking for a more efficient solution? Unless this functionality sits in a very tight inner loop somewhere (e.g. in a ray tracer), you might be trying to prematurely optimize your code.
If you would like to avoid the array, and if you don't like the "bloat" of an if-statement, you can use the ternary choice operator to pick between the two:
int a = 35;
int b = 70;
int c = random.nextBoolean() ? a : b;
where random is an instance of java.util.Random. You can store this instance as a final static field in your class to reuse it.
If you don't require true randomness, but just want to switch between the two numbers in each invocation of the given block of code, you can get away with just storing a boolean and toggling it:
...
int c = toggle ? a : b;
toggle = !toggle;
Since I can't comment on other answers, I'd like to point out an issue with some of the other answers that suggest generating a random integer in a bigger range and making a decision based on whether the result is odd or even, or if it's lower or greater than the middle value. This is in effect the exact same thing as generating a random integer between 0 and 1, except overly complicated. The nextInt(n) method uses the modulo operator on a randomly generated integer between -2^31 and (2^31)-1, which is essentially what you will be doing in the end anyway, just with n = 2.
If you are using the standard library methods like Collections.shuffle(), you will again be overcomplicating things, because the standard library uses the random number generator of the standard library.
Note that all of the suggestions (so far) are less efficient than my simple nextBoolean() suggestion, because they require unnecessary method calls and arithmetic.
Another way to do this is, store the numbers into a list, shuffle, and take the first element.
ArrayList<Integer> numbers=new ArrayList<Integer>();
numbers.add(35);
numbers.add(70);
Collections.shuffle(numbers);
numbers.get(0);
In my opinion, main problem here is entropy for two numbers rather than making use of that entropy. Indexed array or boolean are essentially the same thing. What else you can do (and, hopefully, it will be more random) is to make Java give you a random number between limits say 0 to 100. Now, if the chosen random number is odd, you pick int c = a. Pick b otherwise. I could be wrong, but picking random between 0 to 100 seems more random as compared to picking random between two numbers.
You can simply use secure random generator(java.security.SecureRandom ).
try {
r = SecureRandom.getInstance("SHA1PRNG");
boolean b1 = r.nextBoolean();
if (b1) {
c = a;
} else {
c = b;
}
} catch (NoSuchAlgorithmException nsae) {
// Process the exception in some way or the other
}
Refer this link for more information
Randomize an integer between 1 and 10, if it's more than 5 then take the value of b other wise go with a. As far as I know there are no other ways to select from integers.
int a=1;
int b=2;
int get = new Random().nextBoolean()? a : b;

Creating an even amount of randomness in an array

Let's say that you have an arbitrarily large sized two-dimensional array with an even amount of items in it. Let's also assume for clarity that you can only choose between two things to put as a given item in the array. How would you go about putting a random choice at a given index in the array but once the array is filled you have an even split among the two choices?
If there are any answers with code, Java is preferred but other languages are fine as well.
You could basically think about it in the opposite way. Rather than deciding for a given index, which value to put in it, you could select n/2 elements from the array and place the first value in them. Then place the 2nd value in the other n/2.
A 2-D A[M,N] array can be mapped to a vector V[M*N] (you can use a row-major or a column-major order to do the mapping).
Start with a vector V[M*N]. Fill its first half with the first choice, and the second half of the array with the second choice object. Run a Fisher-Yates shuffle, and convert the shuffled array to a 2-D array. The array is now filled with elements that are evenly split among the two choices, and the choices at each particular index are random.
The below creates a List<T> the size of the area of the matrix, and fills it half with the first choice (spaces[0]) and half with the second (spaces[1]). Afterward, it applies a shuffle (namely Fisher-Yates, via Collections.shuffle) and begins to fill the matrix with these values.
static <T> void fill(final T[][] matrix, final T... space) {
final int w = matrix.length;
final int h = matrix[0].length;
final int area = w * h;
final List<T> sample = new ArrayList<T>(area);
final int half = area >> 1;
sample.addAll(Collections.nCopies(half, space[0]));
sample.addAll(Collections.nCopies(half, space[1]));
Collections.shuffle(sample);
final Iterator<T> cursor = sample.iterator();
for (int x = w - 1; x >= 0; --x) {
final T[] column = matrix[x];
for (int y = h - 1; y >= 0; --y) {
column[y] = cursor.next();
}
}
}
Pseudo-code:
int trues_remaining = size / 2;
int falses_remaining = size / 2;
while (trues_remaining + falses_remaining > 0)
{
if (trues_remaining > 0)
{
if (falses_remaining > 0)
array.push(getRandomBool());
else
array.push(true);
}
else
array.push(false);
}
Doesn't really scale to more than two values, though. How about:
assoc_array = { 1 = 4, 2 = 4, 3 = 4, 4 = 4 };
while (! assoc_array.isEmpty())
{
int index = rand(assoc_array.getNumberOfKeys());
int n = assoc_array.getKeyAtIndex(index);
array.push(n);
assoc_array[n]--;
if (assoc_array[n] <= 0) assoc_array.deleteKey(n);
}
EDIT: just noticed you asked for a two-dimensional array. Well it should be easy to adapt this approach to n-dimensional.
EDIT2: from your comment above, "school yard pick" is a great name for this.
It doesn't sound like your requirements for randomness are very strict, but I thought I'd contribute some more thoughts for anyone who may benefit from them.
You're basically asking for a pseudorandom binary sequence, and the most popular one I know of is the maximum length sequence. This uses a register of n bits along with a linear feedback shift register to define a periodic series of 1's and 0's that has a perfectly flat frequency spectrum. At least it is perfectly flat within certain bounds, determined by the sequence's period (2^n-1 bits).
What does that mean? Basically it means that the sequence is guaranteed to be maximally random across all shifts (and therefore frequencies) if its full length is used. When compared to an equal length sequence of numbers generated from a random number generator, it will contain MORE randomness per length than your typical randomly generated sequence.
It is for this reason that it is used to determine impulse functions in white noise analysis of systems, especially when experiment time is valuable and higher order cross effects are less important. Because the sequence is random relative to all shifts of itself, its auto-correlation is a perfect delta function (aside from qualifiers indicated above) so the stimulus does not contaminate the cross correlation between stimulus and response.
I don't really know what your application for this matrix is, but if it simply needs to "appear" random then this would do that very effectively. In terms of being balanced, 1's vs 0's, the sequence is guaranteed to have exactly one more 1 than 0. Therefore if you're trying to create a grid of 2^n, you would be guaranteed to get the correct result by tacking a 0 onto the end.
So an m-sequence is more random than anything you'll generate using a random number generator and it has a defined number of 0's and 1's. However, it doesn't allow for unqualified generation of 2d matrices of arbitrary size - only those where the total number of elements in the grid is a power of 2.

BigIntegers to the power of BigIntegers

I am trying to implement either the Fermat, Miller-Rabin, or AKS algorithm in Java using the BigInteger class.
I think I have the Fermat test implemented except that the BigInteger class doesn't allow taking BigIntegers to the power of BigIntegers (one can only take BigIntegers to the power of primitive ints). Is there a way around this?
The problematic line is denoted in my code:
public static boolean fermatPrimalityTest(BigInteger n)
{
BigInteger a;
Random rand = new Random();
int maxIterations = 100000;
for (int i = 0; i < maxIterations; i++) {
a = new BigInteger(2048, rand);
// PROBLEM WITH a.pow(n) BECAUSE n IS NOT A BigInteger
boolean test = ((a.pow(n)).minus(BigInteger.ONE)).equals((BigInteger.ONE).mod(n));
if (!test)
return false;
}
return true;
}
I think BigInteger.modPow might be what you're looking for. Note the "mod m" in Fermat's test.
One of the primality tests is built into BigInteger.isProbablePrime(). Not sure which one, you'd have to look at the source.
Also, you can raise a number to a power by multiplying. For example: 2^100 = 2^50 * 2^50. So pull out pieces of your BigInteger power and loop until you've used it up. But are you sure you don't mean to use BigInteger.modPow(), which takes BigIntegers? It looks like you are, based on your test.
You'll have to implement your own pow() method. Look at the sources of BigInteger.pow() as a starting point.

Randomizing a BigInteger

I'm looking to randomize a BigInteger. The intent is to pick a number from 1 to 8180385048. Though, from what I noticed, the BigInteger(BitLen, Random) does it from n to X2-1, I'd want some unpredictable number. I tried to make a method that would do it, but I keep running into bugs and have finally given in to asking on here. :P Does anyone have any suggestions on how to do this?
Judging from the docs of Random.nextInt(int n) which obviously needs to solve the same problem, they seem to have concluded that you can't do better than "resampling if out of range", but that the penalty is expected to be negligible.
From the docs:
The algorithm is slightly tricky. It rejects values that would result in an uneven distribution (due to the fact that 231 is not divisible by n). The probability of a value being rejected depends on n. The worst case is n=230+1, for which the probability of a reject is 1/2, and the expected number of iterations before the loop terminates is 2.
I'd suggest you simply use the randomizing constructor you mentioned and iterate until you reach a value that is in range, for instance like this:
public static BigInteger rndBigInt(BigInteger max) {
Random rnd = new Random();
do {
BigInteger i = new BigInteger(max.bitLength(), rnd);
if (i.compareTo(max) <= 0)
return i;
} while (true);
}
public static void main(String... args) {
System.out.println(rndBigInt(new BigInteger("8180385048")));
}
For your particular case (with max = 8180385048), the probability of having to reiterate, even once, is about 4.8 %, so no worries :-)
Make a loop and get random BigIntegers of the minimum bit length that covers your range until you obtain one number in range. That should preserve the distribution of random numbers.
Reiterating if out of range, as suggested in other answers, is a solution to this problem. However if you want to avoid this, another option is to use the modulus operator:
BigInteger i = new BigInteger(max.bitLength(), rnd);
i = i.mod(max); // Now 0 <= i <= max - 1
i = i.add(BigInteger.ONE); // Now 1 <= i <= max

Categories