I have been reading Algorithms, 4th Edition, and it defines a question as follows:
Write a static method lg() that takes an int value N as an argument and returns the largest int not larger than the base-2 logarithm of N in Java. Do not use Math.
I discovered the following solution:
public static int lg(int N) {
int x = 0;
for (int n = N; n > 1; n/= 2) x++;
return x;
}
I am wondering why that solution works. Why does dividing by 2 continuously allow us to find the largest integer less than the base 2 logarithm of the argument? I do understand Java, just not how this particular algorithm works.
Thank you.
This has to do with properties of exponents and logarithms. The main observation you need is that
2lg n = n,
because logarithms are the inverses of exponentials. Rearranging that expression gives
1 = n / 2lg n.
In other words, the value of lg n is the number of times you have to divide n by two in order to drop it to 1. This, by the way, is a really great intuition to have when studying algorithms, since log terms show up all the time in contexts like these.
There are some other nuances here about how integer division works, but this is the basic idea behind why that code works.
Its follows trivially from the logarithmic identity log(a/b) = log(a) - log(b).
You are searching for the largest integer x so that:
x <= log2(n)
Using the identity above and taking in account that log2(2) = 1 we get:
x <= log2(n/2) + log2(2)
x <= log2(n/2) + 1
x <= log2(n/4) + 2
x <= log2(n/8) + 3
...
x <= log2(1) + k
x <= k (since log2(1) = 0)
So x is the number of times you divided n by 2 before reaching 1.
The answer is purely Mathmatics,
log₂(n) = ln(n)/ln(2) = x
By applying the rules of exponential:
ln(n) = ln(2)*(x)
n = 2^x
Therefore you have to divide by 2 until the value is smaller than 1 in order to get the closest int to it.
We are looking for the largest integer x such that x <= log_2(N) i.e. 2^x <= N
or equivalent 2^x <= N < 2^{x+1}
Let N_0=N
and for k > 0, N_k the quotient of the division of N_{k-1} by 2 and r_k in {0, 1} the remainder (N_{k-1} = 2.N_k + r_k)
We have:
2^{x-1} <= N_1 + (r_1 / 2) < 2^x
But 0 <= r_1 / 2 <= 1/2 and the others numbers are integers so that is equivalent to
2^{x-1} <= N_1 < 2^x
We have successively:
2^{x-1} <= N_1 < 2^x
2^{x-2} <= N_2 < 2^{x-1}
…
2^{x-x} <= N_x < 2^{x-x+1}
The last is also written 1 <= N_x < 2
But N_x is an integer so N_x = 1
Hence x is the number of division by 2 of N remaining greater or equal than 1.
Instead of starting from N_1, we can start from N_0 = N and stay greater than 1.
Related
I have N numbers, and a range, over which I have to permute the numbers.
For example, if I had 3 numbers and a range of 1-2, I would loop over 1 1 1, 1 1 2, 1 2 1, etc.
Preferably, but not necessarily, how could I do this without recursion?
For general ideas, nested loops don't allow for an arbitrary number of numbers, and recursion is undesireable due to high depth (3 numbers over 1-10 would be over 1,000 calls to the section of code using those numbers)
One way to do this, is to loop with one iteration per permuation, and use the loop variable to calculate the values that a permuation is made off. Consider that the size of the range can be used as a modulo argument to "chop off" a value (digit) that will be one of the values (digits) in the result. Then if you divide the loop variable (well, a copy of it) by the range size, you repeat the above operation to extract another value, ...etc.
Obviously this will only work if the number of results does not exceed the capacity of the int type, or whatever type you use for the loop variable.
So here is how that looks:
int [][] getResults(int numPositions, int low, int high) {
int numValues = high - low + 1;
int numResults = (int) Math.pow(numValues, numPositions);
int results[][] = new int [numResults][numPositions];
for (int i = 0; i < numResults; i++) {
int result[] = results[i];
int n = i;
for (int j = numPositions-1; j >= 0; j--) {
result[j] = low + n % numValues;
n /= numValues;
}
}
return results;
}
The example you gave in the question would be generated with this call:
int results[][] = getResults(3, 1, 2);
The results are then:
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
2 2 2
Looked through a few implementation and found, wondering why start iteration from k = m * m is safe? Thanks.
http://www.algolist.net/Algorithms/Number_theoretic/Sieve_of_Eratosthenes
public void runEratosthenesSieve(int upperBound) {
int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
boolean[] isComposite = new boolean[upperBound + 1];
for (int m = 2; m <= upperBoundSquareRoot; m++) {
if (!isComposite[m]) {
System.out.print(m + " ");
for (int k = m * m; k <= upperBound; k += m)
isComposite[k] = true;
}
}
for (int m = upperBoundSquareRoot; m <= upperBound; m++)
if (!isComposite[m])
System.out.print(m + " ");
}
Every composite number less than m*m that m is a factor of, eg. m*n, has a smaller factor than m, eg. n, for which we have already marked it as composite.
This works for prime or composite n, for prime n, we set during the cycle when m=n.
For composite n: We know that any integer > 1 is representable as a product of prime factors. One of these prime factors is the smallest prime factor of n, we'll call this s. Since s is a prime factor of n, we can express n as s*r, for some r. This also means that m*n is m*s*r. s < m as n < m and s < n. We know that r has no prime factors smaller than s, as it was defined this way. So s must be be the smallest prime factor of m*s*r, so we set its iscomposite flag during the cycle for m=s
Lets take a number and factorize it: eg. 120
1 x 120
2 x 60
3 x 40
4 x 30
5 x 24
6 x 20
8 x 15
10 x 12
Now, one observation: sqrt(120) = 11 (taking floor)
Now, next observation, each of the above factors have one thing in common, ie. one of the factors is less than 11 and other is greater than 11.
Now lets factorize 36:
1 x 36
2 x 18
3 x 12
4 x 9
6 x 6
and sqrt(36) = 6. Again we can do a similar observation, that, each one of the factors have one number less than 6 and other greater, except 6 x 6, since 36 is a square.
So, we can easily deduce this:
For any number, if it is not a prime number, we can always find (at least) one of its factor, if we go to its square root.
So, to reduce complexity, we need to go till the square root of every number in the range, so, sqrt(upperBound) is enough for outer loop. That is because, if any number is not marked composite by then, it will never be because we have considered all possible divisors that can be.
EDIT:
Also, this implementation of sieve is not most optimized that can be. Not in terms of asymptotic complexity, but you can do things to reduce few operations. I'll add my implementation of sieve in c++, which calculates all primes till MAX.
#define MAX 1000000
#define I int
#define FOR(i,a,b) for(i=a;i<b;i++)
I p[MAX]={1,1,0}; //global declaration
I prime[MAX/10]={2}; //global declaration
void sieve()
{
I i,j,k=1;
for(i=3;i*i<=MAX;i+=2)
{
if(p[i])
continue;
for(j=i*i;j<MAX;j+=2*i)
p[j]=1;
}
for(i = 3; i < MAX; i+=2)
{
if(!p[i])
prime[k++]=i;
}
return;
}
Im developing an application with java which needs to find two big integers (Y and Z) that meet this two conditions:
Y^k < N and Z^j < N < Z^(j+1)
N, k and j are known. N is a big integer(1024bit).
My current implementations finds Y and Z by choosing a random BigInteger and tests if the conditions are met. But the problem is that sometimes it takes really long to find the solution or it doesn't find one at all (probably the bitSize isn't correctly computed).
Is there any way i could speed this up?
The code:
BigInteger getMessage(int bitSize, int lowerBound, int upperBound, BigInteger module)
{
boolean foundOne = false;
BigInteger candidate = null;
while( !foundOne )
{
candidate = new BigInteger(bitSize,random);
foundOne = (upperBound == 0 || candidate.pow(upperBound).compareTo(module) > 0 ) && (lowerBound == 0 || candidate.pow(lowerBound).compareTo(module) < 0);
}
return candidate;
}
Use binary search. For instance, to find Z, start with Zmin=0 and Zmax=N. Compute Zmid = (Zmin+Zmax)/2, then compare Zmid^j versus N. if Zmin^j < N, then set Zmin=Zmid. Otherwise, set Zmax=Zmid. Eventually you'll narrow down to the correct Z in O(log(N)) time.
One way is to solve the equation directly by taking the logarithm of your expressions:
k * log (Y) < log (N)
=> log (Y) < log (N) / k
j * log (Z) < log (N) < (j + 1) * log (Z)
=> log (Z) < log (N) / j AND log (Z) > log (N) / (j + 1)
Once you have determined a value for log(Y) and log(Z), you can take the exponential (for neperian log or power of 10 for log10) of your result to get back to Y and Z.
You can read here about various ways of calculating the log of a BigInteger. It seems sensible to run the calculation on BigDecimal, then round (up or down) to BigInteger and check that it works.
Don't make it random, make an adjustment to your current guess depending on its relation to the specifications you want to match.
For example, start with n = N/2.
If n^j > N, then lower n by some amount.
If n^j < N, then check n^(j+1) > N.
If n^(j+1) < N, then increase n by some amount.
Etc.
Let's say I have to pick a number from 0-10.
The number I pick is 6.
The next number I want to pick is 0.
Now the rules are I have to keep incrementing the number by 1 or decrementing it by 1, the number can also wrap around the last number.
Now whats most important is to find which direction is shortest to take.
So
6-5-4-3-2-1-0 = 7 moves.
6-7-8-9-10-0 = 6 moves.
So incrementing wins in this case.
Well I came up with this code (probably broken)
int movesInc = 1;
int movesDec = 1;
int curNumber = 6;
int nextNumber = 0;
while((curNumber-- % 11) != nextNumber)
movesDec++;
while((curNumber++ % 11) != nextNumber)
movesInc++;
Now instead of using a while loop in both directions.. and finding out which takes less moves..
any way to do this without a while loop? just maybe some kind of mathematical equation?
Your code doesn't in fact work properly for two reasons:
You should be working modulo 11 instead of 10 (I see you've now fixed this per my earlier comment).
The % operator in Java and C++ doesn't deal with signs the way you think.
This does work, though it's not pretty, and it doesn't need loops.
It is tested for the start at 6 and end at 0, and I expect it works generally. For a different range, you'd of course need to change the number added when the result goes negative.
int curNumber = 6;
int nextNumber = 0;
int movesInc = (nextNumber - curNumber) + 1
+ ((nextNumber > curNumber)? 0: 11);
int movesDec = (curNumber - nextNumber) + 1
+ ((nextNumber < curNumber)? 0: 11);
The + 1 here is because you're counting both endpoints. The ternary expression is what handles going around 0.
int curNumber;
int nextNumber;
//calculate the modulo size by the highest number
int module = 10 + 1;
//calculate the direct distance to the nextNumber
int directDist = nextNumber - curNumber;
int nextNumberWrapped;
//calculate the wrapped distance, deciding the direction which wraps
if(directDist < 0)
//wrapping in positive direction: 10 -> 0
nextNumberWrapped = nextNumber + module;
else
//wrapping in negative direction 0 -> 10
nextNumberWrapped = nextNumber - module;
//calculating the wrapped distance
int wrappedDist = nextNumberWrapped - curNumber;
//assume the directDist to be shortest
int shortestDist = directDist;
//proof wrong if neccessary (compare the distances absolute values)
if(abs(wrappedDist) < abs(directDist))
//save the signed distance
shortestDist = wrappedDist;
The absolute value of shortestDist tells you the length of the shortest distance and the sign gives you the direction.
So when the sign is negative you have to decrement and when it is positive you must increment to go the shortest way.
http://ideone.com/0yCDw
Also your example seems wrong. Each - between the numbers is one step, leaving you with one step less than you counted:
6-5-4-3-2-1-0
^ ^ ^ ^ ^ ^
1 2 3 4 5 6 -> 6 moves
6-7-8-9-10-0
^ ^ ^ ^ ^
1 2 3 4 5 -> 5 moves
Is there any math utility method to calculate the following expression? Basically, I need to find the largest integer less than or equal to x which can be divided by N evenly.
x - x % N; // N is an integer.
For positive integers: (x / N) * N.
(If it needs to be strictly less than x vs <= x then use ((x-1)/N) * N, for x > 0.)
if x is a positive integer and N a power of 2 you can do x & -N
EDIT: its -n not 2-n , thanks to Peter Lawrey for pointing that out
If x is a positive integer then you can use
int result = x - x % N;
or
int result = (x/N)*N;
If x is a positive double then you can use
int result = N * (int)(x/N);