If you know that 'input1' is strictly between 0 and 1 or generally, 'min' and 'max' (where min and max are known to be between, but not strictly, 0 and 1), how would you get 'input1'to increment or decrement by a numerical jump given by 'input2' with assurance that the new value is strictly between min and max and will never reach min or max?
You need a distribution function, preferably an invertible one (the inverse is called quantile function).
In other words, you need a monotone strictly increasing, continuous function f with lim[x->-oo] f(x) = 0 and lim[x->oo] f(x) = 1.
If you have such a distribution function f and its inverse f⁻¹, then your adjusting function gets something like this:
g (x, Δ) = f( f⁻¹(x) + Δ )
This is for values between 0 and 1, for other intervals [a, b] we need to scale it, using a scaling function s:
s(x) = (b-a)·x + a, s⁻¹(y) = (y-a)/(b-a)
Then the adjustment function gets
h(x, Δ) = s(g(s⁻¹(x), Δ) = s( f( f⁻¹(s⁻¹(x)) + Δ )).
One easily Java-calculable such distribution function would be
f(x) = 1 - 0.5 * exp(-x) for 0 ≤ x
f(x) = 0.5 * exp( x) for x ≤ 0
with the quantile function
f⁻¹(y) = - log(2 - 2y) for y ≤ 0.5
f⁻¹(y) = log(2 y) for 0.5 ≤ y
Building from this your adjustment function is just putting these together.
Of course, this works only to the limits of your number precision – you can't get arbitrary close to 1.
I believe the following should keep input1 within min/max
input1 = ((input1 - min + input2) % (max - min)) + min;
You can use min/max like
public static int adjust(int n, int adjust, int min, int max) {
return adjust0(n, adjust, min+1, max-1);
}
private static int adjust0(int n, int adjust, int trueMininum, int trueMaximum) {
return Math.max(trueMininum, Math.min(trueMaximum, n + adjust));
}
This will allows you to adjust your values and be sure it will be between min and max but never those values.
Related
I am trying to solve a problem that I need to get value of three unknowns(x,y,z) knowing some info. their summation is equal to 70, x^2 + y^2 = z^2 and x < y < z.
Answer should be x = 20, y = 21, z = 29
I tried to solve it as two equations in three unknowns but I failed. Any hints to get the solution ? I want to find an algorithm or equation to build a java code that solve this problem
I'll assume that x, y, and z must be positive integers, since removing the integers restriction allows infinitely many solutions. Here is an algorithm--I'll leave the code to you.
Your second equation x^2 + y^2 = z^2 means that x, y, and z form a Pythagorean triple. All solutions to that equation have the form
x = k(m^2 - n^2), y = 2kmn, z = k(m^2 + n^2)
(with possibly x and y swapped) where m, n, and k are positive integers, m > n, one of m and n is even and the other is odd, and (m, n) are relatively prime. You can drop those last two restrictions on m and n, which is to make the triples have unique representation.
Your third limitation x < y < z merely makes a unique triple from the three values. Importantly, your first restriction x + y + z = 70 means that your solution has "small" values.
So in your code, vary the three parameters k, m, and n. There are only finitely many values that allow the sum of x, y, and z to be less than or equal 70, which places limits on k, m, and n. Find the ones that equal make the sum of x, y, and z to be 70. You can cut the number of trials in half by not letting m and n be both even or both odd. You can also avoid explicitly varying k by varying only m and n and calculating what k should be, since each of x, y, z vary proportionally with k, and accept only integral k.
This is somewhat of a brute-force solution, but it is easy to program and will be faster than just trying all values of x, y, and z.
EDIT: I now see that x, y, and z may also be zero. That theoretically means that you need to test for x = 0, but that is clearly impossible here since then y^2 = z^2 which contradicts y < z. So no change is needed to my algorithm.
Expanding on #RoryDaulton's answer, taking x = k(m^2 - n^2), y = 2kmn and z = k(m^2 + n^2) and applying the sum constraint gives us
2*k*m*(m + n) = 70
Or
k * m * (m + n) = 35 = 7 * 5 = 35 * 1
The important thing to note is that the RHS of the above has only two unique factors; the LHS has three. Thus at least one factor of the LHS (k, m, m + n) must be 1.
Since m and n are unique positive integers, m + n will always be greater than 1. Thus,
k = 1 or m = 1
And the only possible values for the remaining LHS factors are 7 and 5 or 35 and 1.
This makes the problem much easier to brute force.
I have solved the question and I want to thank all people who helped me.
This is My code to solve the problem
int x,y,z;
long mul=0;
for(int n=1;n<=sum;n++){
for (int m=2;m<=sum;m++){
x= (int) ((Math.pow(m,2)) - (Math.pow(n,2)));
y= 2*m*n;
z= (int) ((Math.pow(m,2)) + (Math.pow(n,2)));
if(x+y+z == sum){
mul = x*z*y;
}
}}
return mul; }}
A man is keeping score of a football (soccer) game. He tracks partial results like this: 1-0, 1-1, 2-1, 2-2, 3-2. The sum of the goals in all of these partial results is 15, and the final result is 3-2, which is 5 goals. Given N which is sum of the goals of the partial results, you need to find number of goals of the final result. Here are some examples:
Input 15
Output 5
Input 6
Output 3
Input 55
Output 10
I can't use loops to solve the problem; I can only use if/else and arithmetical operations. Using just those operations, how can I find hte number of goals of the final result?
It is a summation problem. A record is created every time a goal is scored. The record is always one larger than the previous record. The total is the sum of all records.
Total = summation( number of goals scored )
So is the total is 1 then you know the number of goals is 1 as well.
If the total is three then there were two goals scored (1 and 1+1)
55 = 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 so there were 10 goals scored.
edit Calculating the actual answer is simpler than using the fractional math shown in other answers, but it requires solving a quadratic equation.
Note that the solution to ax**2 + bx + c == 0 is
x = (-b +/- SQRT( b**2 - 4*a*c) / 2*a
T = n(n+1)/2
2T = n**2 + n
n**2 + n - 2T = 0
n = (-1 +/- SQRT( 1 - 4*1*(-2T))) / (2 * 1), n > 0
n = (SQRT( 1 + 8T ) - 1) / 2
so if T = 10, n = (SQRT(81) - 1) / 2 == 4
r ="result"
s = "sum of goals"
n = "number of goals"
r s n
1-0 1 1
1-1 3 2
2-1 6 3
2-2 10 4
3-2 15 5
This tells us that s is just the sum of the first n integers, but we need n(s), not s(n).
Here's an example calculation.
Here's the code for making this happen in java:
class Example {
public static int n(int s) {
return (int) Math.round(-1.0 / 2.0 + Math.sqrt(1.0 / 4.0 + 2.0 * s));
}
public static int s(int n) {
return (n * (n + 1)) / 2;
}
public static void main(String[] args) {
for (int n = 0; n <= 10; n++) {
int s = s(n);
printResult(s);
}
}
private static void printResult(int s) {
int n = n(s);
System.out.println("If the sum of goals is " + s + ", then the number of goals is " + n);
}
}
Here's the output:
If the sum of goals is 0, then the number of goals is 0
If the sum of goals is 1, then the number of goals is 1
If the sum of goals is 3, then the number of goals is 2
If the sum of goals is 6, then the number of goals is 3
If the sum of goals is 10, then the number of goals is 4
If the sum of goals is 15, then the number of goals is 5
If the sum of goals is 21, then the number of goals is 6
If the sum of goals is 28, then the number of goals is 7
If the sum of goals is 36, then the number of goals is 8
The question is ambiguous as to whether square root is allowed, does it strictly count as an arithmetic operation?
If we assume its not allowed and we cannot use any looping we can use Newton's method to give a good approximation to the answer. Others have pointed out that we are basically trying the find the inverse of the triangular numbers T(n)=n(n+1)/2. If we are given a sum S let f(n)=n^2/2+n/2-S we want to solve f(n)=0. Newton's method is a fast iterative method, given an initial guess x0 we can find a better guess x1 using
x1 = x0 - f(x) / df(x)
where df(x)=x-1/2 is the derivative. If we do this 4 times we get a pretty good solution.
public class InverseSqrt {
static float f(float x,float S) {
return x*x/2+x/2-S;
}
static float df(float x,float S) {
return x+0.5f;
}
static float newton(float sum) {
float x = sum/2; // first initial guess
// Apply Newton's method four time
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
public static void main(String[] args) {
int i=0;
int ires=0;
do { // loop through possible number of goals
++i;
float s = i * (i+1) * 0.5f; // calculate the total
float res = newton(s);
ires = (int) (res+0.5); // round to nearest integer
System.out.print("T("+i+")="+(int)s);
System.out.println("\tres="+ires+"\t("+res+")");
} while(ires==i); // break first time it fails
}
}
This works pretty well up to an input of 351 giving an output of 26. But fails for the next input 378 giving 28 rather than 27 goal.
We can improve things a bit by using 5 steps of Newtons method working up to an input of 1176 with an output of 48. Tuning the initial guess improves things dramatically, using a starting guess of n/16 with 5 steps works upto input 42195 output 290.
A much better solution can be found using the Fast inverse squareroot. This can be implemented in Java following this answer.
static float Q_rsqrt( float x )
{
float xhalf = 0.5f*x;
int i = Float.floatToIntBits(x);
i = 0x5f3759df - (i>>1);
x = Float.intBitsToFloat(i);
x = x*(1.5f - xhalf*x*x);
return x;
}
Our Newton iteration method is then
static float newton(float sum) {
float x = Q_rsqrt(1/sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
with only 3 iteration steps.
This works upto Input 1073720960 Output 46340. The next item after than gives an integer overflow in calculating the sum, so it can be said to work for all legal int values.
This might not be counted as a legal solution as it uses floatToIntBits(x) and intBitsToFloat(x) which don't really class as arithmetic operations.
It seems that sum of arithmetic progression S(n) is given, and you have to find n.
Use simple math and calculate n from equation:
S(n) = n * (n + 1) / 2
I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
Here is what code I have so far.:
static float getRandomNumberInRange(float min, float max) {
return (float) (min + (Math.random() * (max - min)));
}
static float[] randomNums(float a, float b, float c, int n) {
float minDistance = c;
float maxDistance = (b - a) - (n - 1) * c;
float[] randomNumArray = new float[n];
float random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[0] = a + random;
for (int x = 1; x < n; x++) {
maxDistance = (b - a) - (randomNumArray[x - 1]) - (n - x - 1) * c;
random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[x] = randomNumArray[x - 1] + random;
}
return randomNumArray;
}
If I run the function as such (10 times), I get the following output:
Input: randomNums(-1f, 1f, 0.1f, 10)
[-0.88, 0.85, 1.23, 1.3784, 1.49, 1.59, 1.69, 1.79, 1.89, 1.99]
[-0.73, -0.40, 0.17, 0.98, 1.47, 1.58, 1.69, 1.79, 1.89, 1.99]
[-0.49, 0.29, 0.54, 0.77, 1.09, 1.56, 1.69, 1.79, 1.89, 1.99]
I think a reasonable approach can be the following:
Total "space" is (b - a)
Remove the minimum required space (n-1)*c to obtain the remaining space
Shot (n-1) random numbers between 0 and 1 and scale them so that the sum is this just computed "optional space". Each of them will be a "slice" of space to be used.
First number is a
For each other number add c and the next "slice" to the previous number. Last number will be b.
If you don't want first and last to match a and b exactly then just create n+1 slices instead of n-1 and start with a+slice[0] instead of a.
The main idea is that once you remove the required spacing between the points (totalling (n-1)*c) the problem is just to find n-1 values so that the sum is the prescribed "optional space". To do this with a uniform distribution just shoot n-1 numbers, compute the sum and uniformly scale those numbers so that the sum is instead what you want by multiplying each of them by the constant factor k = wanted_sum / current_sum.
To obtain the final result you just use as spacing between a value and the previous one the sum of the mandatory part c and one of the randomly sampled variable parts.
An example in Python of the code needed for the computation is the following
space = b - a
slack = space - (n - 1)*c
slice = [random.random() for i in xrange(n-1)] # Pick (n-1) random numbers 0..1
k = slack / sum(slice) # Compute needed scaling
slice = [x*k for x in slice] # Scale to get slice sizes
result = [a]
for i in xrange(n-1):
result.append(result[-1] + slice[i] + c)
If you have random number X and you want another random number Y which is a minimum of A from X and a maximum of B from X, why not write that in your code?
float nextRandom(float base, float minDist, float maxDist) {
return base + minDist + (((float)Math.random()) * (maxDist - minDist));
}
by trying to keep the base out of the next number routine, you add a lot of complexity to your algorithm.
Though this does not exactly do what you need and does not incorporate the techinque being described in this thread, I believe that this code will prove to be useful as it will do what it seems like you want.
static float getRandomNumberInRange(float min, float max)
{
return (float) (min + (Math.random() * ((max - min))));
}
static float[] randomNums(float a, float b, float c, int n)
{
float averageDifference=(b-a)/n;
float[] randomNumArray = new float[n];
int random;
randomNumArray[0]=a+averageDifference/2;
for (int x = 1; x < n; x++)
randomNumArray[x]=randomNumArray[x-1]+averageDifference;
for (int x = 0; x < n; x++)
{
random = getRandomNumberInRange(-averageDifference/2, averageDifference/2);
randomNumArray[x]+=random;
}
return randomNumArray;
}
I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
First, what distribution? I'm going to assume a uniform distribution, but with that caveat that "any two numbers cannot have a difference of less than c". What you want is called "rejection sampling". There's a wikipedia article on the subject, plus a whole lot of other references on the 'net and in books (e.g. http://www.columbia.edu/~ks20/4703-Sigman/4703-07-Notes-ARM.pdf). Pseudocode, using some function random_uniform() that returns a random number drawn from U[0,1], and assuming a 1-based array (many languages use a 0-based array):
function generate_numbers (a, b, c, n, result)
result[1] = a + (b-a)*random_uniform()
for index from 2 to n
rejected = true
while (rejected)
result[index] = a + (b-a)*random_uniform()
rejected = abs (result[index] < result[index-1]) < c
end
end
Your solution was almost correct, here is the fix:
maxDistance = b - (randomNumArray[x - 1]) - (n - x - 1) * c;
I would do this by just generating n random numbers between a and b. Then I would sort them and get the first order differences, kicking out any numbers that generate a difference less than c, leaving me with m numbers. If m < n, I would just do it again, this time for n - m numbers, add those numbers to my original results, sort again, generate differences...and so on until I have n numbers.
Note, first order differences means x[1] - x[0], x[2] - x[1] and so on.
I don't have time to write this out in C but in R, it's pretty easy:
getRands<-function(n,a,b,c){
r<-c()
while(length(r) < n){
r<-sort(c(r,runif(n,a,b)))
r<-r[-(which(diff(r) <= c) + 1 )]
}
r
}
Note that if you are too aggresive with c relative to a and b, this kind of solution might take a long time to converge, or not converge at all if n * C > b -a
Also note, I don't mean for this R code to be a fully formed, production ready piece of code, just an illustration of the algorithm (for those who can follow R).
How about using a shifting range as you generate numbers to ensure that they don't appear too close?
static float[] randomNums(float min, float max, float separation, int n) {
float rangePerNumber = (max - min) / n;
// Check separation and range are consistent.
assert (rangePerNumber >= separation) : "You have a problem.";
float[] randomNumArray = new float[n];
// Set range for first random number
float lo = min;
float hi = lo + rangePerNumber;
for (int i = 0; i < n; ++i) {
float random = getRandomNumberInRange(lo, hi);
// Shift range for next random number.
lo = random + separation;
hi = lo + rangePerNumber;
randomNumArray[i] = random;
}
return randomNumArray;
}
I know you already accepted an answer, but I like this problem. I hope it's unique, I haven't gone through everyone's answers in detail just yet, and I need to run, so I'll just post this and hope it helps.
Think of it this way: Once you pick your first number, you have a chunk +/- c that you can no longer pick in.
So your first number is
range1=b-a
x=Random()*range1+a
At this point, x is somewhere between a and b (assuming Random() returns in 0 to 1). Now, we mark out the space we can no longer pick in
excludedMin=x-c
excludedMax=x+c
If x is close to either end, then it's easy, we just pick in the remaining space
if (excludedMin<=a)
{
range2=b-excludedMax
y=Random()*range2+excludedMax
}
Here, x is so close to a, that you won't get y between a and x, so you just pick between x+c and b. Likewise:
else if (excludedMax>=b)
{
range2=excludedMin-a
y=Random()*range2+a
}
Now if x is somewhere in the middle, we have to do a little magic
else
{
range2=b-a-2*c
y=Random()*range2+a
if (y>excludedMin) y+=2*c
}
What's going on here? Well, we know that the range y can lie in, is 2*c smaller than the whole space, so we pick a number somewhere in that smaller space. Now, if y is less than excludedMin, we know y "is to the left" of x-c, and we're all ok. However, if y>excluded min, we add 2*c (the total excluded space) to it, to ensure that it's greater than x+c, but it'll still be less than b because our range was reduced.
Now, it's easy to expand so n numbers, each time you just reduce the range by the excluded space among any of the other points. You continue until the excluded space equals the original range (b-a).
I know it's bad form to do a second answer, but I just thought of one...use a recursive search of the space:
Assume a global list of points: points
FillRandom(a,b,c)
{
range=b-a;
if (range>0)
{
x=Random()*range+a
points.Append(x)
FillRandom(a,x-c,c)
FillRandom(x+c,b,c)
}
}
I'll let you follow the recursion, but at the end, you'll have a list in points that fills the space with density 1/c
I need a function to generate random integers. (assume Java long type for now, but this will be extended to BigInteger or BitSet later.)
The tricky part is there is a parameter P that specifies the (independent) probability of any bit in the result being 1.
If P = 0.5 then we can just use the standard random number generator. Some other values of P are also easy to implement. Here's an incomplete example:
Random random = new Random();
// ...
long nextLong(float p) {
if (p == 0.0f) return 0L;
else if (p == 1.0f) return -1L;
else if (p == 0.5f) return random.nextLong();
else if (p == 0.25f) return nextLong(0.5f) & nextLong(0.5f);
else if (p == 0.75f) return nextLong(0.5f) | nextLong(0.5f);
else if (p == 0.375f) return nextLong(0.5f) & nextLong(0.75f); // etc
else {
// What goes here??
String message = String.format("P=%f not implemented yet!", p);
throw new IllegalArgumentException(message);
}
}
Is there a way to generalise this for any value of P between 0.0 and 1.0?
First a little ugly math that you're already using in your code.
Define x and y are bits with probability of being 1 of X = p(x=1), Y = p(y=1) respectively.
Then we have that
p( x & y = 1) = X Y
p( x | y = 1) = 1 - (1-X) (1-Y)
p( x ^ y = 1) = X (1 - Y) + Y (1 - X)
Now if we let Y = 1/2 we get
P( x & y ) = X/2
P( x | y ) = (X+1)/2
Now set the RHS to the probability we want and we have two cases that we can solve for X
X = 2 p // if we use &
X = 2 p - 1 // if we use |
Next we assume we can use this again to obtain X in terms of another variable Z...
And then we keep iterating until we've done "enough".
Thats a bit unclear but consider p = 0.375
0.375 * 2 = 0.75 < 1.0 so our first operation is &
0.75 * 2 = 1.5 > 1.0 so our second operation is |
0.5 is something we know so we stop.
Thus we can get a variable with p=0.375 by X1 & (X2 | X3 )
The problem is that for most variables this will not terminate. e.g.
0.333 *2 = 0.666 < 1.0 so our first operation is &
0.666 *2 = 1.333 > 1.0 so our second operation is |
0.333 *2 = 0.666 < 1.0 so our third operation is &
etc...
so p=0.333 can be generated by
X1 & ( X2 | (X3 & (X4 | ( ... ) ) ) )
Now I suspect that taking enough terms in the series will give you enough accuracy, and this can be written as a recursive function. However there might be a better way that that too... I think the order of the operations is related to the binary representation of p, I'm just not sure exactly how... and dont have time to think about it deeper.
Anyway heres some untested C++ code that does this. You should be able to javaify it easily.
uint bitsWithProbability( float p )
{
return bitsWithProbabilityHelper( p, 0.001, 0, 10 );
}
uint bitsWithProbabilityHelper( float p, float tol, int cur_depth, int max_depth )
{
uint X = randbits();
if( cur_depth >= max_depth) return X;
if( p<0.5-tol)
{
return X & bitsWithProbabilityHelper( 2*p, 0.001, cur_depth+1, max_depth );
}
if(p>0.5+tol)
{
return X | bitsWithProbabilityHelper( 2*p-1, 0.001, cur_depth+1, max_depth );
}
return X;
}
Distribute proportional number of bits throughuot the number.
Pseudocode:
long generateNumber( double probability ){
int bitCount = 64 * probability;
byte[] data = new byte[64]; // 0-filled
long indexes = getRandomLong();
for 0 to bitCount-1 {
do {
// distribute this bit to some postition with 0.
int index = indexes & 64;
indexes >> 6;
if( indexes == 0 ) indexes = getRandomLong();
} while ( data[index] == 0 );
data[index] = 1;
}
return bytesToLong( data );
}
I hope you get what I mean. Perhaps the byte[] could be replaced with a long and bit operations to make it faster.
Here's how I solved it in the end.
Generate an integer N between 0..16, following the binomial distribution. This gives the number of '1' bits in the 16-bit partial result.
Randomly generate an index into a lookup table that contains 16-bit integers containing the desired number of '1' bits.
Repeat 4 times to get four 16-bit integers.
Splice these four 16-bit integers together to get a 64-bit integer.
This was partly inspired by Ondra Žižka's answer.
The benefit is that it reduces the number of calls to Random.nextLong() to 8 calls per 64 bits of output.
For comparison, rolling for each individual bit would require 64 calls. Bitwise AND/OR uses between 2 and 32 calls depending on the value of P
Of course calculating binomial probabilities is just as expensive, so those go in another lookup table.
It's a lot of code, but it's paying off in terms of performance.
Update - merged this with the bitwise AND/OR solution. It now uses that method if it guesses it will be more efficient (in terms of calls to Random.next().)
Use a random generator that generates a uniform float number r between 0 and 1. If r>p then set the bit to 0, otherwise set it to 1
If you're looking to apply some distribution where with probability P you get a 1 and with probability 1-P you get a 0 at any particular bit your best bet is simply to generate each bit independently with probability P of being a 1 (that sounds like a recursive definition, I know).
Here's a solution, I'll walk through it below:
public class MyRandomBitGenerator
{
Random pgen = new Random();
// assumed p is well conditioned (0 < p < 1)
public boolean nextBitIsOne(double p){
return pgen.nextDouble() < p ? true : false;
}
// assumed p is well conditioned (0 < p < 1)
public long nextLong(double p){
long nxt = 0;
for(int i = 0; i < 64; i++){
if(nextBitIsOne(p)){
nxt += 1 << i;
}
}
return nxt;
}
}
Basically, we first determine how to generate a value of 1 with probability P: pgen.nextDouble() generates a number between 0 and 1 with uniform probability, by asking if it's less than p we're sampling this distribution such that we expect to see p 1s as we call this function infinitely.
Here's another variant of Michael Anderson's answer
To avoid recursion, we process the bits of P iteratively from right-to-left instead of recursively from left-to-right. This would be tricky in floating-point representation so we extract the exponent/mantissa fields from the binary representation instead.
class BitsWithProbabilityHelper {
public BitsWithProbabilityHelper(float prob, Random rnd) {
if (Float.isNaN(prob)) throw new IllegalArgumentException();
this.rnd = rnd;
if (prob <= 0f) {
zero = true;
return;
}
// Decode IEEE float
int probBits = Float.floatToIntBits(prob);
mantissa = probBits & 0x7FFFFF;
exponent = probBits >>> 23;
// Restore the implicit leading 1 (except for denormals)
if (exponent > 0) mantissa |= 0x800000;
exponent -= 150;
// Force mantissa to be odd
int ntz = Integer.numberOfTrailingZeros(mantissa);
mantissa >>= ntz;
exponent += ntz;
}
/** Determine how many random words we need from the system RNG to
* generate one output word with probability P.
**/
public int iterationCount() {
return - exponent;
}
/** Generate a random number with the desired probability */
public long nextLong() {
if (zero) return 0L;
long acc = -1L;
int shiftReg = mantissa - 1;
for (int bit = exponent; bit < 0; ++ bit) {
if ((shiftReg & 1) == 0) {
acc &= rnd.nextLong();
} else {
acc |= rnd.nextLong();
}
shiftReg >>= 1;
}
return acc;
}
/** Value of <code>prob</code>, represented as m * 2**e where m is always odd. */
private int exponent;
private int mantissa;
/** Random data source */
private final Random rnd;
/** Zero flag (special case) */
private boolean zero;
}
Suppose the size of bit array is L. If L=1, the chance that the 1st bit is 1 will be P, and that being 0 will be 1-P. For L=2, the probability of getting a 00 is (1-P)2, a 01 or 10 is P(1-P) each and 11 is P2. Extending this logic, we can first determine the first bit by comparing a random number with P, then scale the random number such that we can again get anything between 0 to 1. A sample javascript code:
function getRandomBitArray(maxBits,probabilityOf1) {
var randomSeed = Math.random();
bitArray = new Array();
for(var currentBit=0;currentBit<maxBits;currentBit++){
if(randomSeed<probabilityOf1){
//fill 0 at current bit
bitArray.push(0);
//scale the sample space of the random no from [0,1)
//to [0.probabilityOf1)
randomSeed=randomSeed/probabilityOf1;
}
else{
//fill 1 at current bit
bitArray.push(1);
//scale the sample space to [probabilityOf1,1)
randomSeed = (randomSeed-probabilityOf1)/(1-probabilityOf1);
}
}
}
EDIT:
This code does generate completely random bits. I will try to explain the algorithm better.
Each bit string has a certain probability of occurring. Suppose a string has a probability of occurrence p; we want to choose that string if our random number falls is some interval of length p. The starting point of the interval must be fixed, but its value will not make much difference. Suppose we have chosen upto k bits correctly. Then, for the next bit, we divide the interval corresponding to this k-length bit-string into two parts of sizes in the ratio P:1-P (here P is the probability of getting a 1). We say that the next bit will be 1 if the random number is in the first part, 0 if it is in the second part. This ensure that the probabilities of strings of length k+1 also remain correct.
Java code:
public ArrayList<Boolean> getRandomBitArray(int maxBits, double probabilityOf1) {
double randomSeed = Math.random();
ArrayList<Boolean> bitArray = new ArrayList<Boolean>();
for(int currentBit=0;currentBit<maxBits;currentBit++){
if(randomSeed<probabilityOf1){
//fill 0 at current bit
bitArray.add(false);
//scale the sample space of the random no from [0,1)
//to [0.probabilityOf1)
randomSeed=randomSeed/probabilityOf1;
}
else{
//fill 1 at current bit
bitArray.add(true);
//scale the sample space to [probabilityOf1,1)
randomSeed = (randomSeed-probabilityOf1)/(1-probabilityOf1);
}
}
return bitArray;
}
I am trying to port this algorithm to clojure.
My code is
(defn calc-iterations [x y]
(let [c (struct complex x y)]
(loop [z (struct complex 0 0)
iterations 0]
(if (and (< 2.0 (abs z))
(> max-iterations iterations))
iterations
(recur (add c (multiply z z)) (inc iterations))))))
Multiply, add and abs functions are working as they should. I have tested them with a calculator. However for the following values:
(calc-iterations 0.60703135 -0.33984375) ; should give me 2, instead I get 4
(calc-iterations -1.8421874 0.3515625 ) ; should give me 1, instead I get 3
I am checking the correct iteration numbers using another java applet that I have found on the net. it seems to be working since it produces correct output. Its iteration function is
protected int calcIterations( float x, float y ) {
int iterations = 0;
float xn = x, yn = y;
while ( iterations < MAX_ITERATIONS ) {
float xn1 = xn*xn - yn*yn;
float yn1 = 2*xn*yn;
xn = xn1 + x;
yn = yn1 + y;
float magsq = xn*xn + yn*yn;
if ( magsq > 4 )
break;
iterations++;
}
System.out.println( x + " " + y + " " + iterations );
return iterations;
}
Can anyone spot my error?
I've spotted two differences.
The Java implementation starts at z = (x, y) rather than yours which starts at (0, 0). As your recursive formula is z = z^2 + c, (0, 0)^2 + (x, y) = (x, y) so starting at (x, y) is the same as doing the first iteration. So the number of iterations will come out one less than yours because of this.
The Java implementation increments the number of iterations after checking whether the result, z, is within 2 units from the origin, and doesn't increment it otherwise, whereas yours increments iterations every time. The number of iterations will come out one less than yours because of this also.
So that probably accounts for the differences in your results.
I'd argue that your implementation is more correct, because it distinguishes between the cases where |z| > 2 after one iteration (i.e. where |(x,y)| > 2), and where |z| > 2 after two iterations (i.e. where |(x^2-y^2+x, 2xy+y)| > 2), whereas the Java implementation will perform its first iteration, giving (x^2-y^2+x, 2xy+y), and exit before incrementing the number of iterations, thus not distinguishing between that case.