Get approximate square root - java

I'm implementing Babylonian method to approximate the square root of number n using following formula :
nextGuess = (lastGuess + n / lastGuess) / 2;
So when nextGuess and lasGuess are almost identical, nextGuess is the approximated square root.
What am doing is checking if nextGuess and lastGuess is less than very small number such as 0.0001 then i can claim that nextGuess is the approximated square root of n. if not nextGuess become lastGuess.
So how i can implement that in the right way?
My current code:
public static void getApproximatedSquare(long n){
DecimalFormat decimalFormat = new DecimalFormat("#.####");
decimalFormat.setRoundingMode(RoundingMode.CEILING);
double lastGuess = 1, nextGuess;
nextGuess = (lastGuess + n / lastGuess) / 2;
Double init = 0.0001;
System.out.println(decimalFormat.format(init));
if (Double.valueOf(decimalFormat.format(nextGuess)) <= init)
//todo
}

Current draft of implementation has a few flaws:
I doubt you really need Double.valueOf(decimalFormat.format(...)), it just removes some precision from the result
Your convergence condition is not nextGuess < init but difference_between_nextGuess_and_lastGuess < init
You have to repeat the approximation until convergence, so you can't use just a if. You need a for or while or (as in my solution) do... while
This should work (at each step, it prints last and next guesses)
public static double getApproximatedSquare(long n) {
DecimalFormat decimalFormat = new DecimalFormat("#.####");
decimalFormat.setRoundingMode(RoundingMode.CEILING);
double lastGuess, nextGuess = 1;
double init = 0.0001;
do {
lastGuess = nextGuess;
nextGuess = (lastGuess + (double) n / lastGuess) / 2;
System.out.println(decimalFormat.format(lastGuess)+" ---> "+decimalFormat.format(nextGuess));
} while (Math.abs(lastGuess - nextGuess) >= init);
return nextGuess;
}

Using an absolute tolerance is always a bad idea because it doesn't take into account the order of magnitude of the argument. A relative error is better.
But in the case of the square root, I recommend a much better approach: make sure that your initial approximation is within a factor √2 of the exact root. This is obtained by halving the exponent of 2 in the floating-point representation of the argument. (If you can't access this exponent, you can obtain it by successive divisions or multiplications until to reach the interval [1, 2).)
Example: for 27, you have 16 ≤ 27 < 32. Then 1 ≤ √27 / 4 < √2, and you can start the iterations from 4.
Then perform four iterations of the Babylonian formula. No less, no more.
In the example, after four iterations, you obtain 5.19615242271, which is exact.
If you have the feeling that the successive halving or doubling process is slow and believe that Newton is faster, consider that (x + n / x) / 2 > x / 2, so that Newton actually converges slower than halvings and involves more arithmetic
!

If nextGuess's value is 100% sure to go down and reach a good enough value, can't you just do this?
public static void getApproximatedSquare(long n){
DecimalFormat decimalFormat = new DecimalFormat("#.####");
decimalFormat.setRoundingMode(RoundingMode.CEILING);
double lastGuess = n + 1;
double nextGuess = n;
double init = 0.0001;
while (lastGuess - nextGuess > init)
{
lastGuess = nextGuess;
nextGuess = (lastGuess + n / lastGuess) / 2;
}
System.out.println(decimalFormat.format(init));
}

As nextGuess approaches sqrt(n) from above, you can use this:
double lastGuess = n;
double nextGuess = n;
double epsilon = 1e-4;
while (lastGuess - nextGuess > epsilon) {
lastGuess = nextGuess;
nextGuess = (lastGuess + n / lastGuess) / 2;
}

Related

How do you use double to get the expected result

I was trying out subtracting numbers in java, and this gives me unexpected result
public class FloatWeird
{
public static void main(String[] args)
{
double n = 1;
for(int i = 0;i<10;i++)
{
System.out.println(n);
n = n - 0.10;
}
}
}
Result
1.0
0.9
0.8
0.7000000000000001
0.6000000000000001
0.5000000000000001
0.40000000000000013
0.30000000000000016
0.20000000000000015
0.10000000000000014
I have gone through a few forums and understand that using the BigDecimal class is one solution. However, is there a way to correct it in a simpler way using double as above?
I suggest you use appropriate rounding.
System.out.printf("%.1f%n", n);
When ever you print a double you have to consider what the appropriate round is.
You can also round the result as you calculate which is what BigDecimal does.
n = n - 0.10;
n = Math.round(n * 10) / 10.0;
This will reduce cumulative error.
Another approach is to work in a different unit, e.g. instead of dollar you use cents. This means you can use an int or long and only convert
to dollars for presentation.
long n = 100;
for(int i = 0; i < 10; i++) {
System.out.println(n / 100.0);
n = n - 10;
}
this prints http://ideone.com/Uf70jC
1.0
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
Note: even if you use BigDecimal, this still have to do this except the API can help you determine at what point you should do this.

Java ((4-2) / 4) = 0.0 not 0.5 after casting as double

This method has myNumSides equal to 4, myNumSides is a user-inputted. After myAngle being casted as a double it still returns 0.0 instead of 0.5. Why is this?
public double getMyAngle()
{
int n;
n = myNumSides;
double myAngle = (double) ((n - 2) / n);
return myAngle;
}
Output
Please enter number of sides => 4
Please enter length of each side => 100
Your polygon has 4 sides.
Each side of your polygon has a length of 100.0.
The angle of each vertex is 0.0.
In order to get the correct answer, you would have to do the following:
double myAngle = ((n - 2.0) / n);
OR
double myAngle = ((n - 2) / (double)n);
When java executes double myAngle = (double) ((n - 2) / n);, It will first do the division operation and then do the casting operation. In the division operation you are dividing an Integer by an another Integer. So the result of this division also will be an Integer. In your case case, 2/4 = 0.
Correct code would be do the casting first and then division.
double myAngle = ((double)(n - 2) / n);
If you cast a zero to a double, it's still a zero. What you do with the result has no effect on how it's computed.
You have already performed the math as an int, you then cast that int to a double. This widens the value but does not restore the lost precision to the previously computed value, I suggest you just make n a double like
public double getMyAngle() {
double n = myNumSides;
return ((n - 2) / n);
}
You can change your code to:
public double getMyAngle()
{
int n;
n = myNumSides;
double myAngle = (double)(n - 2)/n;
return myAngle;
}
==================
then the answer should be correct!

How to round integer in java

I want to round the number 1732 to the nearest ten, hundred and thousand. I tried with Math round functions, but it was written only for float and double. How to do this for Integer? Is there any function in java?
What rounding mechanism do you want to use? Here's a primitive approach, for positive numbers:
int roundedNumber = (number + 500) / 1000 * 1000;
This will bring something like 1499 to 1000 and 1500 to 2000.
If you could have negative numbers:
int offset = (number >= 0) ? 500 : -500;
int roundedNumber = (number + offset) / 1000 * 1000;
(int)(Math.round( 1732 / 10.0) * 10)
Math.round(double) takes the double and then rounds up as an nearest integer. So, 1732 will become 173.2 (input parameter) on processing by Math.round(1732 / 10.0). So the method rounds it like 173.0. Then multiplying it with 10 (Math.round( 1732 / 10.0) * 10) gives the rounded down answer, which is 173.0 will then be casted to int.
Use Precision (Apache Commons Math 3.1.1)
Precision.round(double, scale); // return double
Precision.round(float, scale); // return float
Use MathUtils (Apache Commons Math) - Older versions
MathUtils.round(double, scale); // return double
MathUtils.round(float, scale); // return float
scale - The number of digits to the right of the decimal point. (+/-)
Discarded because method round(float,
scale) be used.
Math.round(MathUtils.round(1732, -1)); // nearest ten, 1730
Math.round(MathUtils.round(1732, -2)); // nearest hundred, 1700
Math.round(MathUtils.round(1732, -3)); // nearest thousand, 2000
Better solution
int i = 1732;
MathUtils.round((double) i, -1); // nearest ten, 1730.0
MathUtils.round((double) i, -2); // nearest hundred, 1700.0
MathUtils.round((double) i, -3); // nearest thousand, 2000.0
You could try:
int y = 1732;
int x = y - y % 10;
The result will be 1730.
Edit: This doesn't answer the question. It simply removes part of the number but doesn't "round to the nearest".
At nearest ten:
int i = 1986;
int result;
result = i%10 > 5 ? ((i/10)*10)+10 : (i/10)*10;
(Add zero's at will for hundred and thousand).
why not just check the unit digit...
1. if it is less than or equal to 5, add 0 at the unit position and leave the number as it is.
2. if it is more than 5, increment the tens digit, add 0 at the unit position.
ex: 1736 (since 6 >=5) the rounded number will be 1740.
now for 1432 (since 2 <5 ) the rounded number will be 1430....
I hope this will work... if not than let me know about those cases...
Happy Programming,
very simple. try this
int y = 173256457;int x = (y/10)*10;
Now in this you can replace 10 by 100,1000 and so on....
Its very easy..
int x = 1234;
int y = x - x % 10; //It will give 1230
int y = x - x % 100; //It will give 1200
int y = x - x % 1000; //It will give 1000
The above logic will just convert the last digits to 0. If you want actual round of//
For eg. 1278 this should round off to 1280 because last digit 8 > 5 for this i wrote a function check it out.
private double returnAfterRoundDigitNum(double paramNumber, int noOfDigit)
{
double tempSubtractNum = paramNumber%(10*noOfDigit);
double tempResultNum = (paramNumber - tempSubtractNum);
if(tempSubtractNum >= (5*noOfDigit))
{
tempResultNum = tempResultNum + (10*noOfDigit);
}
return tempResultNum;
}
Here pass 2 parameters one is the number and the other is position till which you have to round off.
Regards,
Abhinav
I usually do it this way:
int num = 1732;
int roundedNum = Math.round((num + 9)/10 * 10);
This will give you 1740 as the result.
Hope this will help.
int val2 = 1732;
val2 = (int)(Math.rint((double) i / 10) * 10);
The output is:1730
Have you looked at the implementation of Mathutils.round() ? It's all based on BigDecimal and string conversions. Hard to imagine many approaches that are less efficient.
Without using any math utils, rounding could be achieved to any unit as below:
double roundValue (double input, double toNearest){
//toNearest is any rounding base like 10, 100 or 1000.
double modValue = input % toNearest;
System.out.println(modValue);
if(modValue == 0d){
roundedValue = input;
}
else
{
roundedValue = ((input - modValue) + toNearest);
}
System.out.println(roundedValue);
return roundedValue;
}

Newton's method with specified digits of precision

I'm trying to write a function in Java that calculates the n-th root of a number. I'm using Newton's method for this. However, the user should be able to specify how many digits of precision they want. This is the part with which I'm having trouble, as my answer is often not entirely correct. The relevant code is here: http://pastebin.com/d3rdpLW8. How could I fix this code so that it always gives the answer to at least p digits of precision? (without doing more work than is necessary)
import java.util.Random;
public final class Compute {
private Compute() {
}
public static void main(String[] args) {
Random rand = new Random(1230);
for (int i = 0; i < 500000; i++) {
double k = rand.nextDouble()/100;
int n = (int)(rand.nextDouble() * 20) + 1;
int p = (int)(rand.nextDouble() * 10) + 1;
double math = n == 0 ? 1d : Math.pow(k, 1d / n);
double compute = Compute.root(n, k, p);
if(!String.format("%."+p+"f", math).equals(String.format("%."+p+"f", compute))) {
System.out.println(String.format("%."+p+"f", math));
System.out.println(String.format("%."+p+"f", compute));
System.out.println(math + " " + compute + " " + p);
}
}
}
/**
* Returns the n-th root of a positive double k, accurate to p decimal
* digits.
*
* #param n
* the degree of the root.
* #param k
* the number to be rooted.
* #param p
* the decimal digit precision.
* #return the n-th root of k
*/
public static double root(int n, double k, int p) {
double epsilon = pow(0.1, p+2);
double approx = estimate_root(n, k);
double approx_prev;
do {
approx_prev = approx;
// f(x) / f'(x) = (x^n - k) / (n * x^(n-1)) = (x - k/x^(n-1)) / n
approx -= (approx - k / pow(approx, n-1)) / n;
} while (abs(approx - approx_prev) > epsilon);
return approx;
}
private static double pow(double x, int y) {
if (y == 0)
return 1d;
if (y == 1)
return x;
double k = pow(x * x, y >> 1);
return (y & 1) == 0 ? k : k * x;
}
private static double abs(double x) {
return Double.longBitsToDouble((Double.doubleToLongBits(x) << 1) >>> 1);
}
private static double estimate_root(int n, double k) {
// Extract the exponent from k.
long exp = (Double.doubleToLongBits(k) & 0x7ff0000000000000L);
// Format the exponent properly.
int D = (int) ((exp >> 52) - 1023);
// Calculate and return 2^(D/n).
return Double.longBitsToDouble((D / n + 1023L) << 52);
}
}
Just iterate until the update is less than say, 0.0001, if you want a precision of 4 decimals.
That is, set your epsilon to Math.pow(10, -n) if you want n digits of precision.
Let's recall what the error analysis of Newton's method says. Basically, it gives us an error for the nth iteration as a function of the error of the n-1 th iteration.
So, how can we tell if the error is less than k? We can't, unless we know the error at e(0). And if we knew the error at e(0), we would just use that to find the correct answer.
What you can do is say "e(0) <= m". You can then find n such that e(n) <= k for your desired k. However, this requires knowing the maximal value of f'' in your radius, which is (in general) just as hard a problem as finding the x intercept.
What you're checking is if the error changes by less than k, which is a perfectly acceptable way to do it. But it's not checking if the error is less than k. As Axel and others have noted, there are many other root-approximation algorithms, some of which will yield easier error analysis, and if you really want this, you should use one of those.
You have a bug in your code. Your pow() method's last line should read
return (y & 1) == 1 ? k : k * x;
rather than
return (y & 1) == 0 ? k : k * x;

Java: Implementing simple equation

I am looking to implement the simple equation:
i,j = -Q ± √(Q2-4PR) / 2P
To do so I have the following code (note: P = 10. Q = 7. R = 10):
//Q*Q – 4PR = -351 mod 11 = -10 mod 11 = 1, √1 = 1
double test = Math.sqrt(modulo(((Q*Q) - ((4*P)*R))));
// Works, but why *-10 needed?
i = (int)(((-Q+test)/(P*2))*-10); // i = 3
j = (int)(((-Q-test)/(P*2))*-10); // j = 4
To put it simply, test takes the first part of the equation and mods it to a non-zero integer in-between 0 and 11, then i and j are written. i and j return the right number, but for some reason *-10 is needed to get them right (a number I guessed to get the correct values).
If possible, I'd like to find a better way of performing the above equation because my way of doing it seems wrong and just works. I'd like to do it as the equation suggests, rather than hack it to work.
The quadratic equation is more usually expressed in terms of a, b and c. To satisfy ax2+bx+c = 0, you get (-b +/- sqrt(b^2-4ac)) / 2a as answers.
I think your basic problem is that you're using modulo for some reason instead of taking the square root. The factor of -10 is just a fudge factor which happens to work for your test case.
You should have something like this:
public static void findRoots(double a, double b, double c)
{
if (b * b < 4 * a * c)
{
throw new IllegalArgumentException("Equation has no roots");
}
double tmp = Math.sqrt(b * b - 4 * a * c);
double firstRoot = (-b + tmp) / (2 * a);
double secondRoot = (-b - tmp) / (2 * a);
System.out.println("Roots: " + firstRoot + ", " + secondRoot);
}
EDIT: Your modulo method is currently going to recurse pretty chronically. Try this instead:
public static int modulo(int x)
{
return ((x % 11) + 11) % 11;
}
Basically the result of the first % 11 will be in the range [-10, 10] - so after adding another 11 and taking % 11 again, it'll be correct. No need to recurse.
At that point there's not much reason to have it as a separate method, so you can use:
public static void findRoots(double a, double b, double c)
{
int squareMod11 = (((b * b - 4 * a * c) % 11) + 11) % 11;
double tmp = Math.sqrt(squareMod11);
double firstRoot = (-b + tmp) / (2 * a);
double secondRoot = (-b - tmp) / (2 * a);
System.out.println("Roots: " + firstRoot + ", " + secondRoot);
}
You need to take the square root. Note that Q^2-4PR yields a negative number, and consequently you're going to have to handle complex numbers (or restrict input to avoid this scenario). Apache Math may help you here.
use Math.sqrt for the square root. Why do you cast i and j to ints? It is equation giving you roots of square function, so i and j can be any complex numbers. You shall limit the discriminant to positive-only values for real (double) roots, otherwise use complex numbers.
double test = Q*Q - 4*P*R;
if(Q < 0) throw new Exception("negative discriminant!");
else {
test = Math.sqrt(test);
double i = (-Q + test) / 2*P;
double i = (-Q - test) / 2*P;
}
Why are you doing modulo and not square root? Your code seems to be the way to get the roots of a quadratic equation ((a±sqrt(b^2-4ac))/2a), so the code should be:
double delta = Q*Q-4*P*R);
if(delta < 0.0) {
throw new Exception("no roots");
}
double d = Math.power(delta,0.5);
double r1 = (Q + d)/(2*P)
double r2 = (Q - d)/(2*P)
As pointed out by others, your use of mod isn't even wrong. Why are you making up mathematics like this?
It's well known that the naive solution to the quadratic equation can have problems if the value of b is very nearly equal to the discriminant.
A better way to do it is suggested in section 5.6 of "Numerical Recipes in C++": if we define
(source: equationsheet.com)
Then the two roots are:
and
Your code also needs to account for pathological cases (e.g., a = 0).
Let's substitute your values into these formulas and see what we get. If a = 10, b = 7, and c = 10, then :
(source: equationsheet.com)
Then the two roots are:
(source: equationsheet.com)
and
(source: equationsheet.com)
I think I have the signs right.
If your calculation is giving you trouble, it's likely due to the fact that you have complex roots that your method can't take into account properly. You'll need a complex number class.

Categories