Adaptive Quadrature Algorithm - Recursive to Iterative - java

I would like to know if it is possible to make this algorithm iterative instead of recursive, and if its posible, could someone help me?.
public static double adaptiveQuadrature(double a, double b) {
double h = b - a;
double c = (a + b) / 2.0;
double d = (a + c) / 2.0;
double e = (b + c) / 2.0;
double Q1 = h / 6 * (f(a) + 4 * f(c) + f(b));
double Q2 = h / 12 * (f(a) + 4 * f(d) + 2 * f(c) + 4 * f(e) + f(b));
if (Math.abs(Q2 - Q1) <= EPSILON)
return Q2 + (Q2 - Q1) / 15;
else
return adaptiveQuadrature(a, c) + adaptiveQuadrature(c, b);
}
static double f(double x) {
return Math.exp( - x * x / 2) / Math.sqrt(2 * Math.PI);
}
Thank you so much for your help!

I don't think so. The size of the steps is depending on function evaluations made at the endpoints of the initial interval, then at the endpoints of subintervals. The pattern is not progressive and you can't organize a single loop that will "guess" the step ahead of time.
Of course you can derecursivate by means of an explicit stack, but that won't essentially change the nature of the process.

Related

Finding the closest point on a line to another point

I have a affine equation y = ax + b where a is the coefficient (coeff).
Let D be a line that goes through axis and described by the previous equation.
I'm trying with this piece of code to find the coordinates of the closest point on D to position (ignoring the y coordinate, because 2D in 3D)
double a = coeff;
double b = position.getZ();
double c = axis.getZ() - axis.getX() * coeff;
double x0 = position.getX();
double y0 = position.getZ();
return new Vector((b * (b * x0 - a * y0) - a * c) / (a * a + b * b), position.getY(),
(a * (-b * x0 + a * y0) - b * c) / (a * a + b * b));
Using this as a refernece
However, this does not work and return weird results
If you stay in vector representation it may be easier.
I have an example code but only in C++ (and Direct3D):
D3DXVECTOR3 ProjectOnLine (const D3DXVECTOR3 &point,
const D3DXVECTOR3 &linePoint,
const D3DXVECTOR3 &lineUnityDir)
{
float t = D3DXVec3Dot(&(point-linePoint), &lineUnityDir);
return linePoint + lineUnityDir*t;
}
If I understand you then your parameters can be used like this:
D3DXVECTOR3 point = position;
D3DXVECTOR3 linePoint = axis;
D3DXVECTOR3 lineUnityDir = D3DXVECTOR3(1, a, 0)/sqrt(1+a*a);

converting python to java float vs double

I need to convert the following python code to Java and remember from the past that handling decimal values must be done carefully otherwise the results will not be accurate.
My question is, can I use doubles for all non-interger values given doubles are more accurate that floats?
Here is my start of the conversion:
Python code
def degrees(rads):
return (rads/pi)*180
def radians(degrees):
return (degrees/180 * pi)
def fnday(y, m, d, h):
a = 367 * y - 7 * (y + (m + 9) // 12) // 4 + 275 * m // 9
a += d - 730530 + h / 24
return a
Java conversion
public double degress(double rads)
{
return (rads/PI)*180;
}
public double radians(double degrees)
{
return (degrees/180 * PI);
}
public double fnday(int y, int m, int d, int h)
{
double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;
a += d - 730530 + h / 24;
return a;
}
I know it may be a simple answer but I need to know the postion of the moon and sun for the app and do not want to rely on an api for this data. I simple want to put in the latitude and longitdue and get the sun and moon rise and set times.
Using a double for each variable would suffice; however, you have an issue that results from integer division:
double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;
If I were you, I'd change y, m, d, and h to all be doubles, so you retain the decimal places when dividing:
public double fnday(double y, double m, double d, double h) {
double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;
a += d - 730530 + h / 24;
return a;
}
If you need a really big precision, the best way is use,
java.lang.BigDecimal, that extends from java.math.Number.
You can even use your existing doubles if you need:
double d = 67.67;
BigDecimal bd = new BigDecimal(d);
But you will need to use the methods from the class like this:
public BigDecimal degress(BigDecimal rads)
{
BigDecimal pi = new BigDecimal(PI);
return (rads.divide(pi))*180;
}

Having trouble solving cubic equations in Java

I'm attempting to follow some psuedo code for solving cubic equations in Mathematics and Physics for Programmers, Chapter 3, as far as I can see I've followed it accurately, but I don't seem to be getting correct outputs.
For example: According to Wolfram Alpha 5x^3 + 4x^2 + 3x + 2 = 0 should give a root of x≈-0.72932, but I'm getting back -1.8580943294965526 from my script.
Can someone help me to work out what the hell I'm doing? I'm following the scripts to get a better understanding of maths and converting equations to code. But this is at the brink of my understanding so I'm finding it troublesome to debug. Coupled with the fact the book has no errata and many online reviews state the book has many errors, I'm struggling to see whether the issue is with my code, the books explanation or both.
The equation given in the book is:
Then if the discriminant > 0 then root has value of r+s:
if discriminant == 0 then there are two roots:
if discriminant < 0 you can find three roots as follows:
After finding t you can transform it to x by taking:
package com.oacc.maths;
public class SolveCubic {
public static double[] solveCubic(double a, double b, double c, double d) {
double[] result;
if (d != 1) {
a = a / d;
b = b / d;
c = c / d;
}
double p = b / 3 - a * a / 9;
double q = a * a * a / 27 - a * b / 6 + c / 2;
double D = p * p * p + q * q;
if (Double.compare(D, 0) >= 0) {
if (Double.compare(D, 0) == 0) {
double r = Math.cbrt(-q);
result = new double[2];
result[0] = 2 * r;
result[1] = -r;
} else {
double r = Math.cbrt(-q + Math.sqrt(D));
double s = Math.cbrt(-q - Math.sqrt(D));
result = new double[1];
result[0] = r + s;
}
} else {
double ang = Math.acos(-q / Math.sqrt(-p * p * p));
double r = 2 * Math.sqrt(-p);
result = new double[3];
for (int k = -1; k <= 1; k++) {
double theta = (ang - 2 * Math.PI * k) / 3;
result[k + 1] = r * Math.cos(theta);
}
}
for (int i = 0; i < result.length; i++) {
result[i] = result[i] - a / 3;
}
return result;
}
public static double[] solveCubic(double a, double b, double c) {
double d = 1;
return solveCubic(a, b, c, d);
}
public static void main(String args[]) {
double[] result = solveCubic(5, 4, 3, 2);
for (double aResult : result) {
System.out.println(aResult);
}
}
}
I also found this code example from the book site(n.b. this is not the psuedo code from the book): http://www.delmarlearning.com/companions/content/1435457331/files/index.asp?isbn=1435457331
on solveCubic(a,b,c,d)
--! ARGUMENTS:
a, b, c, d (all numbers). d is optional (default is 1)
--!
RETURNS: the list of solutions to dx^3+ax^2+bx+c=0
-- if d is defined then divide a, b and c by d
if not voidp(d)
then
if d=0 then return solveQuadratic(b,c,a)
set d to float(d)
set a to a/d
set b to b/d
set
c to c/d
else
set a to float(a)
set b to float(b)
set c to float(c)
end if
set p to b/3 - a*a/9
set q to a*a*a/27 - a*b/6 + c/2
set disc to p*p*p + q*q
if abs(disc)<0.001 then
set r to cuberoot(-q)
set ret to [2*r, -r]
else if disc>0 then
set r to cuberoot(-q+sqrt(disc))
set s to cuberoot(-q-sqrt(disc))
set ret to [r+s]
else
set ang to acos(-q/sqrt(-p*p*p))
set r to 2*sqrt(-p)
set ret to []
repeat with k=-1 to 1
set theta
to (ang - 2*pi*k)/3
ret.add(r*cos(theta))
end repeat
end if
set ret to ret-a/3 --NB: this adds the value to each
element
return ret
end
The error appears to be with the names of the parameters of your solveCubic method.
It seems your book is explaining how to solve the equation x3 + ax2 + bx + c = 0. You are calling your method thinking that the parameters a, b, c and d are for the equation ax3 + bx2 + cx + d = 0. However, it turns out that the body of your method is actually finding solutions to the equation dx3 + ax2 + bx + c = 0.
Aside from this naming error, the calculations appear to be correct. Try plugging your value ≈-1.858 into 2x3 + 5x2 + 4x + 3 if you don't believe me.
If you instead declare your solveCubic method as
public static double[] solveCubic(double d, double a, double b, double c) {
the parameters then correspond to the equation dx3 + ax2 + bx + c. You should then find that your method gives you the answer you expect.
Okay. So, first off the equations from the book seem to be referring to this idea: If you have an equation of the form:
Then by defining t as x - (a/3) you can transform this into an equation with no quadratic term, as verified by a bit of Mathematica:
Once you have no quadratic term, you can then apply the method given; let q be half the constant term, let p be one third the coefficient on the first power term, and define D (discriminant) as p*p*p - q*q.
All else then follows.
So why does your code not work? Because you've mislabeled the variables. a is the coefficient on x^2, not on x^3. If you call your method with the arguments (0.8, 0.6, 0.4, 1) or equivalently with (4, 3, 2, 5), you'll get the right answer.
(Or do as the other answer suggests and more around the variable names in the method declaration)
This works 100%. It has been tried and tested for all combinations.
public void solveCubicEquation(int A, int B, int C, int D) {
double a = (double) B / A;
double b = (double) C / A;
double c = (double) D / A;
System.out.println("Double values: ");
System.out.println(a + " " + b + " " + c);
double p = b - ((a * a) / 3.0);
double q = (2 * Math.pow(a, 3) / 27.0) - (a * b / 3.0) + c;
double delta = (Math.pow(q, 2) / 4) + (Math.pow(p, 3) / 27);
if (delta > 0.001) {
double mt1, mt2;
double t1 = (-q / 2.0) + Math.sqrt(delta);
double t2 = (-q / 2.0) - Math.sqrt(delta);
if (t1 < 0) {
mt1 = (-1) * (Math.pow(-t1, (double) 1 / 3));
} else {
mt1 = (Math.pow(t1, (double) 1 / 3));
}
if (t2 < 0) {
mt2 = (-1) * (Math.pow(-t2, (double) 1 / 3));
} else {
mt2 = (Math.pow(t2, (double) 1 / 3));
}
x1 = mt1 + mt2 - (a / 3.0);
} else if (delta < 0.001 && delta > -0.001) {
if (q < 0) {
x1 = 2 * Math.pow(-q / 2, (double) 1 / 3) - (a / 3);
x2 = -1 * Math.pow(-q / 2, (double) 1 / 3) - (a / 3);
} else {
x1 = -2 * Math.pow(q / 2, (double) 1 / 3) - (a / 3);
x2 = Math.pow(q / 2, (double) 1 / 3) - (a / 3);
}
} else {
System.out.println("here");
x1 = (2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.sin((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))))) - (a / 3.0);
x2 = (-2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.sin((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))) + (Math.PI / 3))) - (a / 3.0);
x3 = (2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.cos((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))) + (Math.PI / 6))) - (a / 3.0);
}
}
Note: will not work for imaginary values

Apache POI rate formula inconsistency with long periods

In order to emulate Excel's rate function, I'm using the Apache POI rate function I grabbed from the svn:
private double calculateRate(double nper, double pmt, double pv, double fv, double type, double guess) {
//FROM MS http://office.microsoft.com/en-us/excel-help/rate-HP005209232.aspx
int FINANCIAL_MAX_ITERATIONS = 20; //Bet accuracy with 128
double FINANCIAL_PRECISION = 0.0000001; //1.0e-8
double y, y0, y1, x0, x1 = 0, f = 0, i = 0;
double rate = guess;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
}
else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = pv + pmt * nper + fv;
y1 = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
// Find root by the Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION) && (i < FINANCIAL_MAX_ITERATIONS)) {
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
}
else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
}
For calculateRate(120, 28.1, -2400, 0, 0, 0.1)), the output is the same as Excel: 0.599
But if I try the same calculation, this time with the values:
calculateRate(360, 15.9, -2400, 0, 0, 0.1))
In Excel I get 0.580, and the program returns -1.1500428517726355. Any hints?
There are a bunch of things that are wrong with this code that you have pasted in your question.
It assumes that a rate is always found (not true) and makes no provision for instances when a rate is not found.
Some of the statements will throw an error which could have been avoided by using a more appropriate programming statement. For instance, take the following statement from your code:
f = Math.exp(nper * Math.log(1 + rate));
This will throw an error when attempting to find Log of a negative or zero value. It could have been rewritten as
f = Math.pow(1 + rate, nper);
The comment in iterative calculations states that it is programming the secant method, yet the iterative calculations are checked for convergence of the wrong variable. It is testing for convergence of a future value when it should be testing for convergence of the interest rate.
I copy pasted your code in Notepad and removed the variable declaration of Java and replaced these with JavaScript variable declarations to test the code with your sample data. And just as I said, the code stops at the second iteration since the difference of future values goes out of error bound and since there is no test in place to see whether a rate is found, the code returns the interest rate as is and one which is wrong.
I am not sure why this code works in instances where it does report a correct rate as is the case with first data set. I would suggest re-coding of the function in a correct manner.
public double rate(double nper, double pmt, double pv)
{
//System.out.println("function rate : " + nper + " " + pmt + " pv " + pv);
double error = 0.0000001;
double high = 1.00;
double low = 0.00;
double rate = (2.0 * (nper * pmt - pv)) / (pv * nper);
while(true) {
// Check for error margin
double calc = Math.pow(1 + rate, nper);
calc = (rate * calc) / (calc - 1.0);
calc -= pmt / pv;
if (calc > error) {
// Guess is too high, lower the guess
high = rate;
rate = (high + low) / 2;
}
else if (calc < -error) {
// Guess is too low, higher the guess.
low = rate;
rate = (high + low) / 2;
}
else {
// Acceptable guess
break;
}
}
//System.out.println("Rate : " + rate);
return rate;
}
Example: =RATE(60, 2112500, 65000000) returns 0.025198; the same with Excel (correct).

How to solve 2D integral?

I've been trying to implement trapezoid rule for double integral. I've tried many approaches, but I can't get it to work right.
static double f(double x) {
return Math.exp(- x * x / 2);
}
// trapezoid rule
static double trapezoid(double a, double b, int N) {
double h = (b - a) / N;
double sum = 0.5 * h * (f(a) + f(b));
for (int k = 1; k < N; k++)
sum = sum + h * f(a + h*k);
return sum;
}
I understand the method for a single variable integral, but I don't know how to do it for a 2D integral, say: x + (y*y).
Could someone please explain it briefly?
If you're intent on using the trapezoid rule then you would do it like so:
// The example function you provided.
public double f(double x, double y) {
return x + y * y;
}
/**
* Finds the volume under the surface described by the function f(x, y) for a <= x <= b, c <= y <= d.
* Using xSegs number of segments across the x axis and ySegs number of segments across the y axis.
* #param a The lower bound of x.
* #param b The upper bound of x.
* #param c The lower bound of y.
* #param d The upper bound of y.
* #param xSegs The number of segments in the x axis.
* #param ySegs The number of segments in the y axis.
* #return The volume under f(x, y).
*/
public double trapezoidRule(double a, double b, double c, double d, int xSegs, int ySegs) {
double xSegSize = (b - a) / xSegs; // length of an x segment.
double ySegSize = (d - c) / ySegs; // length of a y segment.
double volume = 0; // volume under the surface.
for (int i = 0; i < xSegs; i++) {
for (int j = 0; j < ySegs; j++) {
double height = f(a + (xSegSize * i), c + (ySegSize * j));
height += f(a + (xSegSize * (i + 1)), c + (ySegSize * j));
height += f(a + (xSegSize * (i + 1)), c + (ySegSize * (j + 1)));
height += f(a + (xSegSize * i), c + (ySegSize * (j + 1)));
height /= 4;
// height is the average value of the corners of the current segment.
// We can use the average value since a box of this height has the same volume as the original segment shape.
// Add the volume of the box to the volume.
volume += xSegSize * ySegSize * height;
}
}
return volume;
}
Hope this helps. Feel free to ask any questions you may have about my code (warning: The code is untested).
Many ways to do it.
If you already know it for 1d you could make it like this:
write a function g(x) that calculates the 1d integral over f(x,y) for a fixed x
then integrate the 1d integral over g(x)
Success :)
That way you can basically have as many dimensions as you like. Though it scales poorly. For larger problems it might be neccesary to use monte carlo integration.
Consider using the class jhplot.F2D from the DataMelt Java program. You can integrate and visualize 2D functions doing something like:
f1=F2D("x*y",-1,1,-1,1) # define in a range
print f1.integral()

Categories