How to understand Newton's method for square root in Java? - java

public static double sqrt(double c)
{
if (c < 0) return Double.NaN;
double t = c; // line 1
double err = 1e-15; // line 2
while (Math.abs(t - c/t) > err * t) // line 3
t = (c/t + t) / 2.0; // line 4
return t;
}
Q1: I am confused by the variable t in line1 and line 4:
since t = c, then c/t = 1, what does line 4 mean?
Q2: In line 3, what's the purpose to check?
I searched "Newton's method" and got several explanation, but I still could not understand. May I request an straight forward explanation here?

Q1: Note that t changes with each iteration of the loop, so while c/t==1 initially, it won't after that.
Q2: We want the loop to continue until we get an answer "close enough", as defined by err.

The Newton's method is used to approximate real valued functions' roots. See here.
When you are calculating the root to a double value you are actually trying to solve for F(x) = X^2 - C where C is the double and you would be trying to find the x that makes the equation zero.
Now the Newton's Method approximates this by a series of guesses. By each guess(as this function has the appropriate properties), we get closer to the square root. The incremental approximation is actually calculating the tangent to the graph at each guess(t) and then choosing that as a guess at that point and moves closer in steps(c/t + t)/2. At a certain point we get very close and we don't want the function to go on forever so we have line 3 to check that our next estimation has a certain distance from the current approximation. If the next approximation is closer than err*t we don't bother continuing. We are close enough.

Related

Interpretable code using Newton-Raphson Method

I am having troubles with a Java code that must calculate the root square of a given parameter.
However,after some research I found a code that I don't know how was implemented properly.
// read in the command-line argument
double c = Double.parseDouble(args[0]);
double epsilon = 1.0e-15; // relative error tolerance
double t = c; // estimate of the square root of c
// repeatedly apply Newton update step until desired precision is achieved
while (Math.abs(t - c/t) > epsilon *t) {
t = (c/t + t) / 2.0;
}
// print out the estimate of the square root of c
System.out.println(t);
The first thing that I don't understand completely is why they are dividing by two on the 8th line.
t = (c/t + t) / 2.0;
The second thing which I do not understand is the condition from the while loop, to be more precise:
while(Math.abs(t - c/t) > epsilon*t)
Wouldn't be necessary to have only:
while(Math.abs(t - c/t) > epsilon)
t = (c/t + t) / 2.0;
This is used to calculate the average/mean of the two values c/t and t. The value is stored in the variable t for the next loop iteration. Use a System.out.println() call inside the while loop to check the values of t and c/t before this line and the values after this line.

Find the modo value

I have given a log value Y , i want to calculate the anti log of Y i.e
ans = (Math.pow(10,Y))%mod
where mod = 1e9+7 and the anti log of Y will always be integer i.e Y is calculate as follow Y= log(a) a is very large integer of range 10^100000
So for given Y i need to calculate ans ? How to do that considering the mod operation.
My Approach
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))%mod
But it's not correct can someone suggest be efficient approach here ? BigDecimal can be useful there ?
For Example:
Y = 16.222122660468525
Using the straight forward method and rounding off i.e Math.log(10,Y) give me 1667718169966651 but using loops it's give me 16677181699666510. I am not using mod now just explaining that there is an error.
Here Y is small so direct method works and we can take mod easily. if Y is range of 10000 it will not work and overflow so we have to used mod.
I guess it's should work
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))
ans = Math.round(ans)
ans%=mod
There is an error in your judgement here - the loop method is not at fault.
The value of a in your example has 17 integer digits. From this stackoverflow post, a double has ~16 significant digits of precision. Thus both the loop and direct calculations are in fact being limited by lack of precision.
(Just to confirm, using a high precision calculator, the value of a is 16677181699666650.8689546562984070600381634077.... Thus both of your values are incorrect - unless you copied them wrongly?)
Thus your loop method is not the problem; you just need a
higher-precision method to do the last step (calculating pow(10, frac(Y))).
As a side note, there is a more efficient way of doing the loop part - this post has more details.

Math.pow and Math.sqrt work differently for large values?

I'm using Heron's formula to find the area of a triangle. Given sides a, b, and c, A = √(s(s-a)(s-b)(s-c)) where s is the semiperimeter (a+b+c)/2. This formula should work perfectly, but I noticed that Math.pow() and Math.sqrt() give different results. Why does this happen and how can I fix it?
I wrote two methods that find the area and determine if it is an integer.
In this first method, I take the square roots and then multiply them:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.sqrt(s)*Math.sqrt(s-a)*Math.sqrt(s-b)*Math.sqrt(s-c);
return area%1.0==0.0 && area > 0.0;
}
In this second method, I find the product and then take the square root:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.pow(s*(s-a)*(s-b)*(s-c),0.5);
return area%1.0==0.0 && area > 0.0;
}
Can anyone explain why these two methods that are mathematically equivalent give different Values? I'm working on Project Euler Problem 94. My answer comes out to 999990060 the first way and 996784416 the second way. (I know that both answers are very far off the actual)
I would certainly vote for "rounding issues", as you multiply the results of multiple method call in the first method (where every method result gets rounded) compared to the single method call in the second method, where you round only once.
The difference between the answers is larger than I'd expect. Or maybe it isn't. It's late and my mathematical mind crashed a while ago.
I think your issue is with rounding. When you multiply a load of roots together, your answer falls further from the true value.
The second method will be more accurate.
Though, not necessarily as accurate as Euler is asking for.
A calculator is a good bet.
Both methods are problematic. You should in general be very careful when comparing floating point values (that is, also double precision floating point values). Particularly, comparing the result of a computation with == or != is nearly always questionable (and quite often it is just wrong). Comparing two floating point values for "equality" should be done with a method like
private static boolean isEqual(double x, double y)
{
double epsilon = 1e-8;
return Math.abs(x - y) <= epsilon * Math.abs(x);
// see Knuth section 4.2.2 pages 217-218
}
In this case, the floating-point remainder operator will also not have the desired result. Consider the following, classic example
public class PrecisionAgain
{
public static void main(String[] args)
{
double d = 0;
for (int i=0; i<20; i++)
{
d += 0.1;
}
System.out.println(d);
double r = d%1.0;
System.out.println(r);
}
}
Output:
2.0000000000000004
4.440892098500626E-16
In your case, in order to rule out these rounding errors, the return statement could probably (!) something simple like
return (area - Math.round(area) < 1e8);
But in other situations, you should definitely read more about floating point operations. (The site http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html is often recommended, but might be a tough one to start with...)
This still does not really answer your actual question: WHY are the results different? In doubt, the answer is this simple: Because they make different errors (but they both make errors - that's in fact more important here!)

Is there any primitive type that can contain more than one digit after decimal point?

In a program, I need to display the approximate PI value, which is close to 3.141592653.
The program is from The Art and Science of Java Chapter 6 Exercise 3.
Let me outline the exercise. Imagine there is a circle with radius r inscribed inside a square with length of 2r. If a dart is threw in a random fashion, the probability that the dart will fall in the circle is the ratio between the area of the circle and the square, which is PI*r^2/4*r^2, which is the same as PI/4. As a result, the more experiments, the more precise the the value of PI is. Now imagine we are doing it in a coordinates. Randomly choose 2 number, x and y each between -1 and 1. If x^2 + y^2 < 1, the coordinate point will fall into the circle with 1 radius centered in the middle of the coordinates.
Here is the program:
import acm.program.*;
import acm.util.*;
public class ApproxPIValue extends ConsoleProgram{
public void run() {
int total = 0; //calculating the time the dart falls into the circle.
for (int a = 0; a < 10000; a++) {
double x = rgen.nextDouble(-1.0, 1.0);
double y = rgen.nextDouble(-1.0, 1.0);
if ((Math.pow(x, 2) + Math.pow(y, 2)) < 1) {
total++;
}
}
println((double) (total / 10000)*4); // as I mentioned above, the result would be the approximate value of PI/4. By multiplying the result with 4, get the approximate PI value.//
}
/* set RandomGenerator as an instance variable. */
private RandomGenerator rgen = new RandomGenerator();
}
Another question is, is there anyway to print a String without extending any class. As you may notice in the code, I extends ConsoleProgram, which contains the println method. I know there is another method called System.out.print, but when I use it, it doesn't work, even Eclipse doesn't give any warning.
To the question in the title: a double has precision to 15 significant digits, irrespective of where the decimal point is.
In this code
(double) (total / 10000)*4)
you cast the resut of integer operations to a double. The result has 15 significant digits, but the number it represents is an integer. One way to correct is
(total / 10_000.0) * 4
(no need to convert to double explicitly).
Use System.out.println() to immediately see the result on-screen. The PrintStream referred to by System.out is a buffered stream which means it doesn't propagate each character to the screen as it is written. It will flush either when the buffer is full or at the sight of a newline character. This is why System.out.print() does not auto-flush.
Since total is an int, total/10000 uses integer division, i.e. it rounds to zero. You seem to try to use floating point division by casting to double, but the actual division happens before the cast is done. Change that line to
println(((double) total / 10000) *4);
to fix this.
BTW: Java's double has about 16 significant digits.
Re-reading your question, I suspect the problem is this line:
println((double) (total / 10000)*4);
You are dividing one integer with another, which will result in an integer. You then cast that to a double, but by then the damage is done.
To solve this, force the compiler to treat the 10000 value as a double. This will ensure the result is a double.
println((total / 10000d)*4);

Problems with NaN

I've been having problems with my code for two weeks, and have been unsuccessful in debugging it. I've come here in the hope that someone can help. I've written a program that utilizes the Barnes-Hut algorithm for n-body gravitational simulation. My problem is that one or more 'particles' will have the position of {NaN, NaN, NaN} assigned to them (using three doubles to represent x, y, z of 3-d space). This, in turn, causes the other particles to have an acceleration of {NaN, NaN, NaN}, and in turn, a velocity and position of {NaN, NaN, NaN} as well. Basically, after a frame or two, everything disappears. It seems to be occurring in the updateAcc method, but I have a feeling that this isn't so. I understand that this is a huge undertaking, and am very grateful for anyone that helps me.
What I've checked:
There are no negative square roots, and all the values seem to be within their limits.
The source code is available here. Thanks again.
Code that seems to produce NaN:
private static void getAcc(particle particle, node node)
{
if ((node.particle == null && node.children == null) || node.particle == particle)
{
//Geting gravity to a node that is either empty or the same node...
}
else if (distance(node.centerOfMass, particle.position) / node.sideLength > theta && node.children != null)
{
for (int i = 0; i < node.children.length; i++)
{
if (node.children[i] != null)
{
getAcc(particle, node.children[i]);
}
}
}
else
{
particle.acceleration = vecAdd(particle.acceleration, vecDiv(getForce(particle.position, particle.mass, node.centerOfMass, node.containedMass), particle.mass));
}
}
private static double sumDeltaSquare(double[] pos1, double[] pos2)
{
return Math.pow(pos1[0]-pos2[0],2)+Math.pow(pos1[1]-pos2[1],2)+Math.pow(pos1[2]-pos2[2],2);
}
private static double[] getForce(double[] pos1, double m1, double[] pos2, double m2)
{
double ratio = G*m1*m2;
ratio /= sumDeltaSquare(pos1, pos2);
ratio /= Math.sqrt(sumDeltaSquare(pos1,pos2));
return vecMul(vecSub(pos2, pos1), ratio);
}
private static double distance(double[] position, double[] center)
{
double distance = Math.sqrt(Math.pow(position[0]-center[0],2) + Math.pow(position[1]-center[1],2) + Math.pow(position[2]-center[2],2));
return distance;
}
I'm not sure if this is the only problem, but it is a start.
sumDeltaSquare will sometimes return 0 which means when the value is used in getForce ratio /= sumDeltaSquare(pos1, pos2); it will produce Infinity and start causing issues.
This is a serious problem that you need to debug and work out what everything means. I enjoyed looking at the dots though.
Firstly, why aren't you using Java's Vecmath library? (It's distributed as a part of Java3D. Download Java3D's binary build and then just use vecmath.jar) Your problem is, very likely, somewhere in your custom vector functions. If not, #pimaster is probably right in that your translation magnitude method sumDeltaSquare might be returning 0 if two of your masses occupy a single space. Which means, unless you're inside a black hole, you're doing it wrong :P. Or you need to come up with a quantum gravity theory before you can do this simulation.
If you can't use vecmath (i.e. this is a homework assignment) I would suggest you use a regex to find every instance of return * and then replace it with assert !Double.isNan(*) && Double.isFinite(*);\nreturn *, except substitute * for whatever regex finds a "match group". I've forgotten exactly what that is, but I got you started on Google. I also suggest you avoid optimizations until after you have working code.
I'm not going to debug your code. But NaN values are the result of mathematically invalid operations on floating point numbers. The most famous of those is division by 0 (does not throw an exception with floating point).
How can this happen?
If your computation produces very small numbers, they might become too small to be represented as 64-bit floating point numbers (they require more bits than are available), and Java will return 0.0 instead.
In the other direction, if you get an overflow (the magnitude of the number requires too many bits), Java turns this into infinity. Doing math with infinity and 0 can quickly lead to NaN, and NaN propagates through every operation you apply to it.
For details, see sections 4.2 and 15.17 of the Java language spec.

Categories

Resources