Difference in calculating middle index of array? - java

I have been trying to solve QuickSort and I got thru a scenario where we are selecting pivot element as the middle one.
http://www.java2novice.com/java-sorting-algorithms/quick-sort/
// calculate pivot number, I am taking pivot as middle index number
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
How difference this is with the below way to get the middle index?
int pivot = array[(lowerIndex+higherIndex)/2];
I remember I have seen this many times before also. And I am sure I am missing a scenario where this helpful when we get a odd number or something.
I tried few sample values but I get the same response for both ways.
What am I missing?
Thanks for your respone.

It is more likely that
(lowerIndex+higherIndex)/2
overflows rather than
lowerIndex+(higherIndex-lowerIndex)/2.
For example for lowerIndex == higherIndex == Integer.MAX_VALUE / 2 + 1.
Edit:
Mathematical proof of equivalence of the expressions
l + (r - l)/2 (in java notation)
= l + round_towards_zero((r - l) / 2) (in math notation)
= round_towards_zero(l + (r - l) / 2) (since l is an integer)
= round_towards_zero((2 * l + r - l) / 2)
= round_towards_zero(r + l) / 2)
= (l + r) / 2 (in java notation)

Related

How to set the mid element when doing a binary search?

This may sound very naive question. Please excuse me for that. I was working on a problem that involved binary search. And the general way to do that I had learned is
set low = 0, set high = array.Length - 1
while(low < high)
mid = (low+high)/2
if (array[mid] == element) return mid
if (array[mid] > element) set start = mid +1
if array[mid] < element ) set high = mid
Please note the way i am setting the mid point. But some of example/solution that I saw sets the mid differently and I am not able to wrap my head around that. Please see the code snippet below. Any explanation what does setting the mid = l + (r-l)/2 mean would be greatly appreciated.
int BinarySearch(int A[], int l, int r, int key)
{
int m;
while( l <= r )
{
m = l + (r-l)/2;
if( A[m] == key ) // first comparison
return m;
if( A[m] < key ) // second comparison
l = m + 1;
else
r = m - 1;
}
return -1;
}
The goal in both cases is to find the middle element.
(low + high) / 2: The sum of the left and right indices is divided by 2 to get the mid point. The problem with this is that the sum could overflow.
If the sum is an even number, we pick the lower one. Example - With left and right as [2, 5] - We pick mid as 3
l + (r - l) / 2: The difference between the right and the left index is found and is divided by 2. It is then added to the left index to find the midpoint. It might be easier to visualize this with an example.
Example : [5, 11] -> (11 - 5) / 2 = 3 The middle in this interval is now 3 places or hops from the left index. So, add the left index to find the index of the mid element which is 5 + 3 = 8
Middle is equal to the starting index of the left value plus the range between right and left divided by two.
Say our range is 5 to 10.
5 + (10-5)/2 == 5 + 5/2 == 5 + 2.5 == 7.5, the middle of our range
This trick is done to avoid integer overflow problem .
(i)use unsinged right shift operator
int mid=(high+low)>>>1
or
(ii) int mid=low +(high-low)/2
(low+high)/2 will overflow if the sum exceeds Integer.MAX_VALUE and you will get wrong results or an RuntimeException
You can read this article by Josh Bloch:
https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html

java StdDraw formula for ratio [duplicate]

How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.

Solve harmonic-factorial sequence with java recursion

I'm trying to understand reqursion, but I have found one task, I couldn't solve for few days already.
X = 1/1 + 1/(1*2) + 1/(1*2*3) + 1/(1*2*3*4) + 1/(1*2*3*4*5) .....
how can I solve it for 100 repeats without conditional operators?
Can it be solved without recursion?
I've tried this code, but it doesn't work correctly and it contains "If".
public static double harFac(double n) {
if (n == 1) return 1;
return (1.0 / (n * harFac(n - 1))) + harFac(n - 1);
}
I believe you could do something like this:
double result = 0;
int div = 1;
for (int i = 1; i <= 100; i++){
result += 1.0 / div; /*the division needs to take place in floating point*/
div *= i+1;
}
You'll very quickly run into trouble if you evaluate the denominator like that as it will run to a limit very quickly. When working with floating point, it's also a good idea to evaluate the smaller terms first.
Fortunately you can solve both of these problems by recasting the expression to
1 * (1 + 1/2 * ( 1 + 1/3 * (1 + 1/4 * ( ... ) ) ) )
So your final term is in the recursion is foo = 1 + 1.0/100, the penultimate term in the recursion is 1 + 1/98 * foo, and so on.
I personally wouldn't use recursion to solve this, rather use a loop in a single function.
You're along the right lines but you shouldn't be calling harFac twice. You need to instead calculate the divisor. I can't see how you would do this without an if condition, though.
public static double harFac(double n)
{
if (n == 1) return 1;
int divisor = 1;
for (int i = 2; i <= n; ++i) divisor *= i;
return (1.0 / divisor) + harFac(n - 1);
}
This doesn't work beyond around n = 30 because the divisor becomes so massive.

Java For-loop changes numeric result when changing type of loop variable

I wrote a program to calculate the PI number with Leibniz formula:
[
I wrote a for-loop with type of initialization is "int" , the loop works fine but when i changed the initialization type to "long" the result is changed. This only happens when the loop times over a billion. This makes the "int - loop" calculates PI more accurate than "long - loop". I don't know why this happens. Please help me to understand this issue. Thanks! and here is my code.
public static void main(String[] args) {
double result1 = 0;
double result2 = 0;
double sign = 1;
for (int i = 0; i <= 1607702095; i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
sign = 1;
for (long j = 0; j <= 1607702095; j++) {
result2 += sign/(2 * j + 1);
sign *= -1;
}
System.out.println("result1 " + result1 * 4);
System.out.println("result2 " + result2 * 4);
System.out.println("pi " + Math.PI);
}
And the result is:
result1 3.141592653576877
result2 3.1415926529660116
pi 3.141592653589793
Actually, your first loop would have int overflow in the calculation of (2 * i + 1) when i is large enough, so I wouldn't rely on the output of it.
The second loop, on the other hand, produces a more correct output, since (2 * j + 1) doesn't overflow, since it performs long multiplication.
This makes the "int - loop" calculates PI more accurate than "long - loop"
That's probably just a coincidence, since the calculations in the int loop overflow.
Because you are getting overflow at the line
result1 += sign/(2 * i + 1);
Where the value of 2*i cross the max integer value
int range is -2,147,483,648 to 2,147,483,647 but when you do 2*i for greater value it crosses that range.
Better to be stick with long and that gives you correct output.
2 * i when i is close to the end of your loop will overflow the max value for an int which is 2147483647.
Using a long that operation doesn't overflow.
The correct procedure is using a long type. Probably because values are added and removed around the correct PI for some strange behavior the overflows momentarily compute to a value closer to the right PI.
I suppose that change the limit of the for loop of few values will change the final result to a value that is more far from the right PI.
You have integer overflow.
The max capacity of a signed int is (2^31)-1, or 2,147,483,647.
(1,607,702,095 * 2) is 3215404190, which is bigger than 2,147,483,647.
When you change i to a long you increase the capacity of i to (2^63)-1.
Noticed everyone is pointig the integer overflow, but you might want a solution. (If you already have one, please ignore the following :) )
Having the overflow in the (2 * i + 1) part of the code, you should max the i in the for loop to (Integer.MAX_VALUE / 2 - 1), which results in:
for (int i = 0; i <= (Integer.MAX_VALUE / 2 - 1); i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
You can also do that to the long part with (Long.MAX_VALUE / 2 - 1) but it will be running for a VERY LONG time.

Overflow of integer in Java

I was asked this in an interview.
I was asked to compute the average of numbers x1,x2,x3,...xn
class Iterator {
bool hasNext;
int getNext();
}
// So it came down to something like this:
double average (Iterator & it) {
double average = 0;
double sum = 0;
int len = 0;
while (it.hasNext == true) {
sum += it.getNext();
}
if (len > 0)
average = sum / len;
}
The interviewer said the list size is unkown and it can be very big, so sum can overflow. He asked how do I solve the overflow problem, I answered by keeping track of how may times we exceed the max number and so forth, he said something about pushing into stack, the average and length, I never really understood his solution by pushing these 2 variables into some sort of list? Anyone has a clue?
I don't know about using a stack, but with some help from algebra, we can derive a formula for the new average, using the old average.
Let's say you have already averaged n - 1 items, and you have that average in oldAvg.
oldAvg = (x1 + x2 + .. + xn - 1) / (n - 1)
The new average would be represented by newAvg:
newAvg = (x1 + x2 + .. + xn - 1 + xn) / n
With some algebraic manipulation, we can represent the new average using the old average the number of items averaged, and the next item.
newAvg = (x1 + x2 + .. + xn - 1) / n + xn / n
= ((n - 1)/(n - 1)) * (x1 + x2 + .. + xn - 1) / n + xn / n
= oldAvg / n * (n - 1) + xn / n
This can avoid overflow by dividing by n before multiplying by n - 1. Then all you have to do is add in the next item, xn, divided by n.
The first loop would establish the average as equal to the first element, but each subsequent loop would use the formula above to derive the new average.
n++;
newAvg = oldAvg / n * (n - 1) + it.next() / n;
He was probably referring to the fact that you don't need all the terms to compute an average, you can instead keep track of a moving average. That can be used along with the number of terms so far considered to come up with the sum of the terms.
Since the total could be too large to store as a long, you'd want to use something like a BigInteger to hold the total.
If you simplify rgettman's formula further you will get following:
len++;
average = average + (it.next() - average) / len;

Categories

Resources