Finding the square root of a number by using binary search - java

I tried using binary search to find the square root of an integer, but some how I couldn't pass a few test cases.
I was able to pass mySqrt(4) = 2, but I wasn't able to pass mySqrt(2147395599)
Any ideas on where I messed up?
public static int mySqrt(int x) {
int left = 0;
int right = x;
if(x < 2){
return x;
}
while(left < right){
int mid = left + ((right - left) / 2);
if(mid * mid == x){
return mid;
}
else if(mid * mid < x){
left = mid + 1;
}
else{
right = mid;
}
}
return left - 1;
}

Because mid * mid will overflow. You should use long to avoid the overflow. Then cast it back to int when you return the result.
Try this code
public static int mySqrt(int x) {
long left = 0;
long right = x;
if(x < 2){
return x;
}
while(left < right){
long mid = left + ((right - left) / 2);
if(mid * mid == x){
return (int)mid;
}
else if(mid * mid < x){
left = mid + 1;
}
else{
right = mid;
}
}
return (int)(left - 1);
}

Here is a version which handles doubles.
It is recursive.
It computes until a given precision is reached.
for (int i = 2; i < 10; i++) {
System.out.println("sqrt("+i+") = " + sqrt(i));
}
Prints
sqrt(2) = 1.414213562373095
sqrt(3) = 1.7320508075688772
sqrt(4) = 2.0
sqrt(5) = 2.23606797749979
sqrt(6) = 2.449489742783178
sqrt(7) = 2.6457513110645907
sqrt(8) = 2.82842712474619
sqrt(9) = 3.0
public static double sqrt(double i) {
return bsqrt(i, 0, i, 0);
}
static double prec = 10E-200;
private static double abs(double d) {
return d < 0 ? -d : d;
}
private static double bsqrt(double i, double low, double high,
double last) {
double mid = (high + low) / 2;
double d = last - mid;
if (d < 0) {
d = -d;
}
if (d < prec) {
return mid;
}
double sqr = mid * mid;
if (sqr < i) {
return bsqrt(i, mid, high, mid);
} else {
return bsqrt(i, low, mid, mid);
}
}
But a better way is to use Newton's method.
static double prec = 10E-15;
public static double newtons(double i) {
// initial guess
double x = i / 2;
double d = i;
double nx = 0;
while (abs(d) > prec) {
nx = x - (x*x - i)/(2*x);
d = nx - x;
x = nx;
}
return nx;
}

This is like a binary search
The following code computes the [integer] square root of a number. If the number is not a
perfect square (there is no integer square root) , then it returns -1. It does this by successive
guessing. If n is 100, it first guesses SO. Too high? Try something lower - halfway between 1
and SO. What is its runtime?
int sqrt(int n) {
return sqrt_helper(n, 1, n);
}
int sqrt_helper(int n, int min, int max) {
if (max < min) return -1; // no square root
int guess = (min + max) / 2·,
if (guess *guess == n) { // found it!
return guess;
}else if (guess * guess < n) { II too low
return sqrt_helper(n, guess + 1, max); // try higher
} else { // too high
return sqrt_helper(n, min, guess - l); //try lower
}
}
credits: cracking the coding interview

Related

Implement floored square root using binary search

Okay, so I've been working on this for some time now and I know that my logic is correct, however, I can't seem to produce the correct floored square root of a positive number.
public int mySqrt(int x) {
if(x < 2) return x;
double lowerBound = 0.0, upperBound = x, midPoint = 0.0;
while(lowerBound <= upperBound) {
midPoint = lowerBound + (upperBound - lowerBound) / 2;
double square = Math.pow(midPoint, 2);
if(Double.compare(square, x) < 0) lowerBound = midPoint + 1;
else if(Double.compare(square, x) > 0) upperBound = midPoint - 1;
else return (int) midPoint;
}
return (int) midPoint;
}
A test case I fail, for example, is for x = 2: it should return 1 but I return 2. which doesn't make sense because I clearly take a midPoint first. Is the logic to go left or right incorrect?
Since you are performing binary search on a double value, you should set a tolerance, and stop looping once the difference between high and low drops below that tolerance (a standard tolerance would usually be 1e-6). You also should set low = mid or high = mid instead of adding or subtracting one, as you are not binary searching over int values. See the below code in action here.
private static final double TOLERANCE = 1e-10;
public int mySqrt(int x) {
if (x < 2)
return x;
double lowerBound = 0.0, upperBound = x, midPoint = 0.0;
while (upperBound - lowerBound >= TOLERANCE) {
midPoint = lowerBound + (upperBound - lowerBound) / 2;
double square = Math.pow(midPoint, 2);
if (Double.compare(square, x) < 0)
lowerBound = midPoint;
else if (Double.compare(square, x) > 0)
upperBound = midPoint;
else
return (int) midPoint;
}
return (int) midPoint;
}
If you never anticipate needing more precision, you can just binary search using ints. See the below code in action here.
public int mySqrt(int x) {
if (x < 2)
return x;
int low = 0, high = x;
while (low < high - 1) {
final int mid = low + high >>> 1;
if (mid <= x / mid) {
low = mid;
} else {
high = mid;
}
}
return low;
}
You shouldn't be using any double math for this. You have to do a lot more iterations to get an accurate double value, and then you just throw it away. You should use an integer solution like this:
int mySqrt(int x) {
if (x<2) {
return x;
}
int minval=1, maxval=x/2;
while(minval < maxval) {
// rounding up here means we never choose minval
int test = minval + (maxval - minval + 1)/2;
// testing this way avoids a multiply that could overflow
if (x/test < test) {
//too high
maxval = test-1;
} else {
//not too high
minval = test;
}
}
return minval;
}
Since the input is int and the result is int, this shouldn't involve floating point arithmetic at all.
public static int mySqrt(int i) {
if (i < 2)
return i;
int lower = 0, upper = i;
do {
int guess = lower + (upper - lower) / 2;
if(guess <= i / guess) {
lower = guess;
} else {
upper = guess;
}
} while ((upper - lower) > 1);
return lower;
}

Writing a Power method with a minimum amount of steps n(log)N

I'm trying to write the Power method and now the question is how to write it in a better way. Here is my code, I've verified it works well for all the Power conditions, however I can't think on a better solution.
The real issue is how I express the power with a Negative exponent in O(log)n condition
public static double raiseToPowerIterative(double x, int n) {
double sol = 1;
if (n == 0) {
return 1;
}
if (n > 0) {
for (int i = 1; i <= n;i++) {
sol *= x;
}
return sol;
} else if (n < 0){
for (int i = -1; i >= n; i--) {
sol /= x;
}
}
return sol;
}
You need some additional math rules, you are using:
xn = x.x. ... .x (n times)
With O(n)
However
x2k = xk . xk
x2k+1 = x.x2k
Which can deliver O(²log n), as you are doing exponents n → n/2 → n/2/2 → ... → 1.
Where you only need to calculate xk once.
A recursive solution might be easiest; calling oneself for xk.
Your solution:
That does not work, I think. As probably past limit date of the work.
Wrong:
double power(double x, int n) {
if (n == 0) {
return 1;
}
boolean negative = ( n < 0 );
if (negative) {
n = -n;
}
double sol = 1;
while (n > 0) {
if (n%2 == 1) {
sol *= x;
}
x *= x;
n /= 2;
}
if (negative) {
return 1 / sol;
}
return sol;
}
Correct recursive:
double power(double x, int n) {
if (n == 0) {
return 1;
} else if (n < 0) {
return 1 / power(x, -n);
}
double sqrPower = power(x, n/2);
int p = sqrPower * sqrPower;
if (n % 1 == 1) {
p *= x;
}
return p;
}
That is, one has to do something with the result of the recursive call.
For an iterative loop one would need a stack to reconstruct the result.
Correct iterative:
double power(double x, int n) {
if (n == 0) {
return 1;
}
boolean invert = n < 0;
if (invert) {
n = -n;
}
Stack<Double> factors = new Stack<>();
while (n > 0) {
factors.push(n % 1 == 1 ? x : 1.0);
n /= 2;
}
double sol = 1;
while (!factors.empty()) {
double f = factors.pop();
sol = sol * sol * f;
}
return invert ? 1/sol : sol;
}

Implementation of sinus function | Calculation Time

Can anybody tell me why this code doesn't work? I'm trying to implement a sinus-function with a given limitation of precision (by the error-variable).
Certain details about the calculation are given here: https://en.wikipedia.org/wiki/Taylor_series
berechnePot calculates the potence
berechneFak calculates the faculty
berechneVZW calculates the pre sign (plus or minus)
I don't get the point, why the function is calculating that slow.
public class Sinus {
public static double sinus(double x) {
double error = 0.001;
double summand = 0;
double sum = 0;
int k = 0;
do {
double pot = 0;
double fak = 0;
pot = berechnePot(x, k);
fak = berechneFak(k);
summand = pot / fak;
berechneVZW(summand, k);
sum += summand;
k++;
} while (abs(summand) > error);
return sum;
}
public static double abs(double value) {
if (value < 0) return -value;
else return value;
}
public static double berechneVZW(double value, int k) {
if (k % 2 == 0) {
return value;
} else {
return value *= (-1);
}
}
public static double berechnePot(double x, double k) {
double pot = 0;
pot += x;
for (int i = 0; i <= k; i++) {
pot *= (x * x);
}
return pot;
}
public static double berechneFak(int k) {
double fak = 1;
if (k == 0) {
return 1;
} else {
for (int i = 0; i <= k; k++) {
fak *= (2 * i + 1);
}
}
return fak;
}
}
Finally i got to the right solution..
I hope that the new structure helps you to better understand my implementation better.
Thanks for all your help!
public class Sinus {
public static double sinus(double x) {
double error = 0.00001;
double summand = 0;
double result = 0;
double fak = 0;
int k = 0;
do {
double pot = 0;
pot = calcNumeratorPotency(x, k);
fak = calcDenumeratorFaculty(k);
summand = pot / fak;
summand = definePreSign(summand, k);
result += summand;
k++;
} while (absoluteValue(summand) > error);
return result;
}
public static double absoluteValue(double value) {
if (value < 0)
return -value;
else
return value;
}
public static double definePreSign(double value, int k) {
if (k % 2 == 0) {
return value;
} else {
return value * (-1);
}
}
public static double calcNumeratorPotency(double x, double k) {
double pot = x;
for (int i = 0; i < 2 * k; i++) {
pot *= x;
}
return pot;
}
public static double calcDenumeratorFaculty(int k) {
double fak = 1;
if (k == 0) {
return 1;
} else {
for (int i = 1; i <= (2 * k + 1); i++) {
fak *= i;
}
}
return fak;
}
You seem to have worked with another language before. Java works a bit different than you seem to expect.
for (int i = 0; i <= k; k++) {
fak *= (2 * i + 1);
}
This particular loop is definetly not working as expected. You increment k, but iis supposed to grow? Might be you want to write:
for (int i = 0; i <= k; i++) {
fak *= (2 * i + 1);
}
Because the loop counts k, instead of i, it continues, until k overruns the integer-range and becomes Integer.MIN_VALUE. At that point, your loop finally terminates. :)
On a completely different note, and meant as constructive critique: You might want to take a look at the default Java-Style-Guide (https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/styleguide.md)
Small excerpt:
// Bad.
// - This offers poor visual separation of operations.
int foo=a+b+1;
// Good.
int foo = a + b + 1;
Spaces between identifiers and operators are very, very helpful, operating with numbers, but also with a lot of different stuff.
It is not quite clear to me what you are calculating in berechnePot and berechnePot. They seem to be the numerators and denominators, judging from the context.
Running your code with a debugger, I can see that summand is calculated very wrongly, and decreases very slowly. This is the reason why it takes so long.
The Math class provides a pow method, so you don't really need to use a for loop to calculate powers. I think you might be overcomplicating this a bit. I would write a getSummand method and a factorial method:
private static double getSummand(double x, int k) {
int power = k * 2 + 1;
double numerator = Math.pow(x, power);
double denominator = factorial(power);
int sign = k % 2 == 1 ? -1 : 1;
return numerator / denominator * sign;
}
private static double factorial(int x) {
double result = 1;
for (int i = 1; i <= x; i++) {
result *= i;
}
return result;
}
And use them like this:
public static double sinus(double x) {
double error = 0.001;
double summand = 0;
double sum = 0;
int k = 0;
do {
summand = getSummand(x, k);
sum += summand;
k++;
} while (Math.abs(summand) > error);
return sum;
}
If this is an assignment and you are not allowed to use anything from the Math class, you could write your own pow method like this:
private static double pow(double x, int p) {
double result = 1;
for (int i = 0 ; i < p ; i++) {
result *= x;
}
return result;
}
In your berechneFak() function you have a loop inside the else clause. You do increment k but not i so i <= k is always true. Try looking at it in a debugger. This is the loop that is slowing it down.
So every time k will count up to the max integer value of 2,147,483,647 in single increments and then overflow to a negative value at which point the loop will end.
Just to clarify: I did not look at if the math is correct but just at why the program is slow.

Getting the first occurrence in binary search

I am trying to get the first occurrence of the number 5.The answer should be 2 in this case but i am getting 3 here.
public static void main(String[] args) {
int A[] = {1, 3, 5, 5, 5, 17, 20};
int index = BinarySearch(A, 5);
System.out.println(index);
}
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
while (low <= high) {
//(low + high) / 2
int mid = low + (high-low)/2; // more optimal -> low + (high-low)/2 (avoid integer overflow)
if (x == A[mid]) {
return mid;
} else if (x < A[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
When you find the value you are looking for, you return the mid index immediately without checking if there are smaller indices having the same value.
You have to continue searching :
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
int mid = -1;
while (low <= high) {
mid = low + (high-low)/2;
if (x <= A[mid]) { // this ensures you keep searching for the first index having
// the number you are looking for
//
// changing x <= A[mid] to x < A[mid] will give you the
// last index having the number you are looking for instead
high = mid - 1;
} else {
low = mid + 1;
}
}
if (mid >= 0 && x == A[mid]) {
return mid;
}
return -1;
}

Bruteforce and Conquer and Divide not giving same distance answer for Closest Pair of Points

I created a program that generates a user inputted number of pairs of points. It then goes through a bruteforce and divide and conquer methods to find the closest pair of points. The bruteforce method works perfectly. The divide and conquer method on the other hand gives me an output but it is different than the brute force distance almost 90% of the time. I can't seem to figure out why it is like this in my code. NOTE: Some of the comments in the functions are from my teacher. Also, the closest_pair function along with rec_cl_pair have been given to me by my teacher where I must use them but had to adjust to my code (they were pseudo code for most part).
My code is:
import java.util.*;
import static java.lang.Math.min;
public class ClosestPair{
private Double x;
private Double y;
private static Double minDist = Double.POSITIVE_INFINITY;
private static ClosestPair closestPair1 = new ClosestPair(0.0,0.0);
private static ClosestPair closestPair2 = new ClosestPair(0.0,0.0);
public ClosestPair(Double x, Double y){
this.x = x;
this.y = y;
}
public static void main(String[] args) {
Double rangeMin = 0.0;
Double rangeMax = 1000.0;
Random r = new Random();
Scanner scan = new Scanner(System.in);
System.out.print("\nEnter the number of two dimensional arrays: ");
int dim = scan.nextInt();
ClosestPair[] pair = new ClosestPair[dim];
ClosestPair[] pairCopy = new ClosestPair[dim];
for(int i = 0; i < dim; i++){
Double xVal = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
Double yVal = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
pair[i] = new ClosestPair(xVal,yVal);
//System.out.print(pair[i].x + ", " + pair[i].y + "\n");
}
/*
for(int j = 0; j < pair.length; j++){
System.out.print(pair[j].x + ", " + pair[j].y + "\n");
}
*/
pairCopy = pair;
pair = mergeSort(pair);
/*
System.out.print("\n\n\n");
for(int j = 0; j < pair.length; j++){
System.out.print(pair[j].x + ", " + pair[j].y + "\n");
}
*/
//BRUTE FORCE PRINT STATEMENTS
long startTime = System.nanoTime();
bruteForce(pair);
long endTime = System.nanoTime();
long timeSpent = endTime - startTime;
System.out.print("\nMin Distance = " + minDist);
System.out.print("\n(x1,y1) = " + closestPair1.x + ", " + closestPair1.y);
System.out.print("\n(x2,y2) = " + closestPair2.x + ", " + closestPair2.y);
System.out.print("\nTime: " + timeSpent + "\n\n");
minDist = 0.0;
//CONQUER DIVIDE PRINT STATEMENTS
startTime = System.nanoTime();
minDist = closest_pair(pairCopy);
endTime = System.nanoTime();
timeSpent = endTime - startTime;
System.out.print("Min Distance = " + minDist);
System.out.print("\nTime: " + timeSpent);
scan.close();
}
private static void bruteForce(ClosestPair[] pair) {
for(int i = 1; i < pair.length - 1; i++){
for(int j = i + 1; j < pair.length; j++){
ClosestPair p = new ClosestPair(pair[i].x,pair[i].y);
//System.out.print("\np:" + pair[i].x + ", " + pair[i].y);
ClosestPair q = new ClosestPair(pair[j].x,pair[j].y);
//System.out.print("\nq: " + pair[j].x + ", " + pair[j].y);
if(getDistance(p, q) < minDist){
minDist = getDistance(p, q);
closestPair1.x = p.x;
closestPair1.y = p.y;
closestPair2.x = q.x;
closestPair2.y = q.y;
}
}
}
}
private static Double getDistance(ClosestPair p1, ClosestPair p2) {
double xdist = p2.x - p1.x;
double ydist = p2.y - p1.y;
return Math.hypot(xdist, ydist);
}
static ClosestPair[] mergeSort(ClosestPair[] a) {
if (a.length > 1) {
int q = a.length/2;
ClosestPair[] leftArray = Arrays.copyOfRange(a, 0, q);
ClosestPair[] rightArray = Arrays.copyOfRange(a,q,a.length);
mergeSort(leftArray);
mergeSort(rightArray);
a = merge(a,leftArray,rightArray);
}
return a;
}
static ClosestPair[] merge(ClosestPair[] a, ClosestPair[] l, ClosestPair[] r) {
int totElem = l.length + r.length;
//int[] a = new int[totElem];
int i,li,ri;
i = li = ri = 0;
while ( i < totElem) {
if ((li < l.length) && (ri<r.length)) {
if (l[li].x < r[ri].x) {
a[i] = l[li];
i++;
li++;
}
else {
a[i] = r[ri];
i++;
ri++;
}
}
else {
if (li >= l.length) {
while (ri < r.length) {
a[i] = r[ri];
i++;
ri++;
}
}
if (ri >= r.length) {
while (li < l.length) {
a[i] = l[li];
li++;
i++;
}
}
}
}
return a;
}
//START OF CONQUER DIVIDE SECTOIN
static double closest_pair(ClosestPair[] p){
int n = p.length - 1;
p = mergeSortDC(p, 0, n); // sort all n points by x-coordinate
return rec_cl_pair(p, 0, n);
}
static double rec_cl_pair(ClosestPair[] p, int i, int j){ // finds closest pair between points in p[i..j]
// assumes input is sorted by x-coordinate
// at termination, input is sorted by y-coordinate
// i is the left index of the subarray, j is the right index
if (j - i < 3){ // at most 3 points in p[i..j]
p = mergeSortDC (p, i, j); // sort p[i..j] by y-coordinate
double delta = getDistance(p[i], p[i+1]);
if (j - i == 1) { // two points
minDist = delta;
return delta;
}
else{
double min1 = min(getDistance(p[i+1], p[i+2]), getDistance(p[i], p[i+2]));
minDist = min(delta,min1);
return minDist;
}
}
int m = (i + j)/2;
double line = p[m].x;
double deltaL = rec_cl_pair(p, i, m); // p[i..m] is sorted by y-coordinate
double deltaR = rec_cl_pair(p, m+1, j); // p[m+1..j] is sorted by y-coordinate
double delta = min(deltaL, deltaR);
p = mergeDC(p, i, m, j); // p[i..j] is now sorted by y-coordinate
// Of points in p[i..j], find points in vertical strip of width 2*delta,
// centered at line (middle of x-values), and store in array v
int t = 0;
ClosestPair[] v = new ClosestPair[j+1];
for(int k = i; k < j; k++){
if ((p[k].x > line - delta) && (p[k].x < line + delta)){
t = t + 1;
v[t] = p[k];
}
}
// Find closest pairs among points in array v. NOTE: Cool math shows
// there are at most 8 points in the strip at distance < delta. Thus,
// in the loops below, each point is compared to at most 7 other points.
for(int k = 1;k < t-1; k++){
for(int s = k+1; k < min(t,k+7); s++){ // inner loop iterates <= 7 times
delta = min(delta, getDistance(v[k],v[s]));
minDist = delta;
return delta;
}
}
return minDist;
}
private static ClosestPair[] mergeSortDC(ClosestPair[] p, int low, int high) {
// check if low is smaller then high, if not then the array is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
mergeSortDC(p, low, middle);
// Sort the right side of the array
mergeSortDC(p, middle + 1, high);
// Combine them both
p = mergeDC(p, low, middle, high);
}
return p;
}
private static ClosestPair[] mergeDC(ClosestPair[] p, int low, int middle, int high) {
ClosestPair[] helper = new ClosestPair[p.length];
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
helper[i] = p[i];
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest values from either the left or the right side back
// to the original array
while (i <= middle && j <= high) {
if (helper[i].x <= helper[j].x) {
p[k] = helper[i];
i++;
} else {
p[k] = helper[j];
j++;
}
k++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
p[k] = helper[i];
k++;
i++;
}
return p;
}
}
An example of output is:
Enter the number of two dimensional arrays: 50
Min Distance = 19.014027210555614
(x1,y1) = 76.99595098629398, 600.1657767818473
(x2,y2) = 87.04091889578226, 616.3098732403395
Time: 3852815
Min Distance = 29.457199999686082
Time: 414081
The first min distance is the bruteforce result. The second is the divide and conquer result

Categories

Resources