I need some insight on my recursive method of calculating the sin Taylor series, which doesn't work properly. The method calls two other recursive methods which are a recursive pow method and a recursive factorial method. I compared my findings with an iterative sin method giving me the correct solution. What is missing in my recursive sin method ?
Approximation of sin(x)= x - x^3/3! + x^5/5! -x^7/7!+ ...
public class SinApprox
{
public static void main (String [] args)
{
Out.println(sinx(1, 1, 2, 1, 1, 0, 1));
Out.print(sinIT(2));
}
static double sinIT(double x)
{
double sin = 0;
double a = x;
double b = 1;
double term = a/b;
double vz = 1;
double i = 1;
while(term > 0.000001)
{
i = i +2;
sin = sin + (term*vz);
a= rekursivPow(x,i);
b = rekursivN(i);
term = a/b;
vz = -1 * vz;
}
return sin;
}
static double rekursivN(double n)
{
if(n==1)
{
return 1;
}
return n * rekursivN(n-1);
}
static double rekursivPow(double x , double y)
{
if(y == 1)
{
return x ;
}
return x * rekursivPow(x , y - 1);
}
static double sinx(double i ,double n, double x, double y, double vz, double sum, double pow)
{
double term = pow / n;
if(term > 0.000001)
{
sum = sum + (term * vz);
vz = -1 * vz;
i = i +2;
n = rekursivN(i);
y = y +2;
pow = rekursivPow(x ,y);
return sinx(i, n, x , y , vz, sum, pow);
}
return sum;
}
}
Step one would be to write out the function in a way that makes the recursive relationship clear (you can't write code for what isn't clear) so, don't start with this:
sin(x)= x - x^3/3! + x^5/5! -x^7/7!+ ...
But instead, ask "how can I make all those terms with x look the same":
sin(x)= x^1/1! - x^3/3! + x^5/5! + ...
Good start, but if we're recursing, what we're really looking for is something that only computes one of those terms, and then calls itself with updated arguments to compute the next term. Ideally, we want something like:
doThing(args) {
return simpleComputation() + doThings(updatedargs);
}
And then recursion does the rest. So let's first make sure that we only ever have to deal with + instead of a mix of + and -:
sin(x)= (-1)^0 * x^1/1! + (-1)^1 * x^3/3! + (-1)^2 * x^5/5! + ...
And now you have something you can actually express as a recursive relation, because:
sin(x,n) {
return (-1)^n * x^(2n+1) / (2n+1)! + sin(x, n+1);
}
With the "shortcut" function:
sin(x) {
return sin(x,0);
}
And that's where the hints stop, you should be able to implement the rest yourself. As long as you remember to stop the recursion because a Taylor series is infinite, and computer programs and resources are not.
Related
I am using mclaurins series to calculate arccos(x^2-1) but when i compare it to a result of math.acos it differs.
Here is my code:
public class Maclaurin {
public static int factorial(int fact) {
if(fact==0)
return 1;
return fact*factorial(fact-1);
}
public static void main(String[] args) {
int i, j;
double function = 0, x,result;
x=0;
for (int n = 0; n < 8; n++) {
function=((factorial(2*n))/(Math.pow(4, n)*Math.pow(factorial(n),2)*(2*n+1)))*Math.pow((Math.pow(x, 2)-1),2*n+1);
result=(Math.PI/2)-function;
System.out.println("x= "+x+" y= "+result);
System.out.println("Test "+Math.acos(Math.pow(x, 2)-1));
x+=0.13;
}
}
}
Programm output. test is a value calculated with Math.arccos and it differs from y calculated with mclaurins formula:
x= 0.0 y= 2.5707963267948966
Test 3.141592653589793
x= 0.13 y= 1.7291549939933966
Test 2.9574849820283498
x= 0.26 y= 1.6236496851024964
Test 2.771793621843802
x= 0.39 y= 1.5848621264898726
Test 2.5828078861333155
x= 0.52 y= 1.5725761587226181
Test 2.3885331918392687
x= 0.65 y= 1.5708496332463704
Test 2.1864594293995867
x= 0.78 y= 1.570796415168701
Test 1.9731661516473589
x= 0.91 y= 1.5707963267948972
Test 1.7435543826662978
EDIT:New code where calculations are in maclaurin function and i call it from main function. works good for all values except first 3:
package maclaurin;
public class Maclaurin {
private static double x;
//public static int factorial(int fact) {
// if(fact==0)
// return 1;
// return fact*factorial(fact-1);
//}
public static double factorial(int fact) {
if(fact==0)
return 1;
return fact*factorial(fact-1);
}
public static void main(String[] args)
{
x = 0;
for (int i=0;i<8;i++)
{
maclaurin(x);
x=x+0.14;
}
}
public static void maclaurin(double value){
double function = 0, x, result;
x =value;
for (int n = 0; n < 20; n++) {
function += ((factorial(2 * n)) / (Math.pow(4, n) * Math.pow(factorial(n), 2) * (2 * n + 1)))
* Math.pow((Math.pow(x, 2) - 1), 2 * n + 1);
}
result = (Math.PI / 2) - function;
System.out.println("x= " + x + " y= " + result);
System.out.println("Test " + Math.acos(Math.pow(x, 2) - 1));
}
}
The factorial of 16, which appears in your loop, is greater than MAX_INT.
I get:
>> factorial(16)
2.0923e+013
>> 2^31
2.1475e+009
in Octave. You need to do an analytic simplification to keep that in range or use double instead of int there.
I think you don't understand, what maclaurin series (taylor's series) is actually do. It can calculate an approximate value. You will get the exact value only for n -> ∞. Since we can't calculate that, we need to define some n and stop our calculation there. You have to add every single part of the summ to get the actual value. So basically you should iterate over n and ADD the calculated value to function and after the loop you can calculate result:
public static void main(String[] args){
double x = 0;
for(int i = 0;i < 8;i++){
System.out.println("x: " + x + " maclaurin: " + maclaurin(x));
System.out.println("Test: " + Math.acos(Math.pow(x, 2) - 1));
x += 0.14;
}
}
public static double maclaurin(double x){
double function = 0;
for (int n = 0; n < 10; n++) {
function += ((factorial(2 * n)) / (Math.pow(4, n) * Math.pow(factorial(n), 2) * (2 * n + 1)))
* Math.pow((Math.pow(x, 2) - 1), 2 * n + 1);
}
return (Math.PI / 2) - function;
}
this way I got pretty close values:
x: 0.0 maclaurin: 2.962490972738185
Test: 3.141592653589793
x: 0.14 maclaurin: 2.8972172328920296
Test: 2.9432779368601296
x: 0.28 maclaurin: 2.7366715068800485
Test: 2.7429790581451043
x: 0.42000000000000004 maclaurin: 2.5381695201901326
Test: 2.5385256934250617
x: 0.56 maclaurin: 2.3273181153351756
Test: 2.327323409412957
x: 0.7000000000000001 maclaurin: 2.105981109221438
Test: 2.1059811170704963
x: 0.8400000000000001 maclaurin: 1.8696239609917407
Test: 1.8696239609918046
x: 0.9800000000000001 maclaurin: 1.6104066839613247
Test: 1.6104066839613247
it seems, that result is not as good for x close to 0. You can increase n to get better results, but at some point you will get NaN, since factorial will overflow at some point.
don't forget to change factorial like #Brick suggested:
public static double factorial(int fact) {
if(fact==0)
return 1;
return fact*factorial(fact-1);
}
if you wonder how to calculate factorial in an iterative way, here is an example(it actually doesn't matter in this particular case, but hey, we are here to learn new things, right?):
public static double factorial(int fact) {
double result = 1;
while(fact > 1){
result *= fact--;
}
return result;
}
EDIT: changed fact parameter to int
EDIT2: wrapped maclaurin function and added more values
EDIT3: added iterative factorial
In a program, a double is being converted to BigDecimal. This returns a very strange error message.
public static double riemannFuncForm(double s) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*
(Math.sin((Math.PI*s)/2))*gamma(1-s);
if(s == 1.0 || (s <= -1 && s % 2 == 0) )
return 0;
else if (s >= 0 && s < 2)
return getSimpsonSum(s);
else if (s > -1 && s < 0)
return term*getSimpsonSum(1-s);
else
return term*standardZeta(1-s);
}
BigDecimal val = BigDecimal.valueOf(riemannFuncForm(s));
System.out.println("Value for the Zeta Function = "
+ val.toEngineeringString());
This returns
Exception in thread "main" java.lang.NumberFormatException
What is causing this error message? Does BigDecimal.valueOf(double) not work correctly since this is referenced through another method?
Full program
/**************************************************************************
**
** Euler-Riemann Zeta Function
**
**************************************************************************
** XXXXXXXXXX
** 06/20/2015
**
** This program computes the value for Zeta(s) using the standard form
** of Zeta(s), the Riemann functional equation, and the Cauchy-Schlomilch
** transformation. A recursive method named riemannFuncForm has been created
** to handle computations of Zeta(s) for s < 2. Simpson's method is
** used to approximate the definite integral calculated by the
** Cauchy-Schlomilch transformation.
**************************************************************************/
import java.util.Scanner;
import java.math.*;
public class ZetaMain {
// Main method
public static void main(String[] args) {
ZetaMain();
}
// Asks the user to input a value for s.
public static void ZetaMain() {
double s = 0;
double start, stop, totalTime;
Scanner scan = new Scanner(System.in);
System.out.print("Enter the value of s inside the Riemann Zeta " +
"Function: ");
try {
s = scan.nextDouble();
}
catch (Exception e) {
System.out.println("You must enter a positive integer greater " +
"than 1.");
}
start = System.currentTimeMillis();
if (s == 1)
System.out.println("The zeta function is undefined for Re(s) " +
"= 1.");
else if (s < 2) {
BigDecimal val = BigDecimal.valueOf(riemannFuncForm(s));
System.out.println("Value for the Zeta Function = "
+ val.toEngineeringString());
}
else
System.out.println("Value for the Zeta Function = "
+ BigDecimal.valueOf(getStandardSum(s)).toString());
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form of the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
// Returns the value calculated by the Standard form of the Zeta function.
public static double getStandardSum(double s){
return standardZeta(s);
}
// Approximation of the Gamma function through the Lanczos Approximation.
public static double gamma(double s){
double[] p = {0.99999999999980993, 676.5203681218851,
-1259.1392167224028, 771.32342877765313,
-176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6,
1.5056327351493116e-7};
int g = 7;
// Implements Euler's Reflection Formula.
if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)
*gamma(1-s));
s -= 1;
double a = p[0];
double t = s + g + 0.5;
for(int i = 1; i < p.length; i++){
a += p[i] / (s+i);
}
return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)
*Math.exp(-t)*a;
}
/* Riemann's Functional Equation - Directly calculates the value of
Zeta(s) for s < 2.
1. The first if statement handles the case when s < 0 and s is a
multiple of 2k. These are trivial zeroes where Zeta(s) is 0.
2. The second if statement handles the values of 0 < s < 2. Simpson's
method is used to numerically compute an approximation of the
definite integral.
3. The third if statement handles the values of -1 < s < 0. Recursion
is used alongside an approximation through Simpson's method.
4. The last if statement handles the case for s <= -1 and is not a
trivial zero. Recursion is used directly against the standard form
of Zeta(s).
*/
public static double riemannFuncForm(double s) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*
(Math.sin((Math.PI*s)/2))*gamma(1-s);
if(s == 1.0 || (s <= -1 && s % 2 == 0) )
return 0;
else if (s >= 0 && s < 2)
return getSimpsonSum(s);
else if (s > -1 && s < 0)
return term*getSimpsonSum(1-s);
else
return term*standardZeta(1-s);
}
// Returns the function referenced inside the right hand side of the
// Cauchy-Schlomilch transformation for Zeta(s).
public static double function(double x, double s) {
double sech = 1 / Math.cosh(x); // Hyperbolic cosecant
double squared = Math.pow(sech, 2);
return ((Math.pow(x, s)) * squared);
}
// Simpson's rule - Approximates the definite integral of f from a to b.
public static double SimpsonsRule(double a, double b, double s, int n) {
double simpson, dx, x, sum4x, sum2x;
dx = (b-a) / n;
sum4x = 0.0;
sum2x = 0.0;
// 4/3 terms
for (int i = 1; i < n; i += 2) {
x = a + i * dx;
sum4x += function(x,s);
}
// 2/3 terms
for (int i = 2; i < n-1; i += 2) {
x = a + i * dx;
sum2x += function(x,s);
}
// Compute the integral approximation.
simpson = function(a,s) + function(a,b);
simpson = (dx / 3)*(simpson + 4 * sum4x + 2 * sum2x);
return simpson;
}
// Handles the error for for f(x) = t^s * sech(t)^2. The integration is
// done from 0 to 100.
// Stop Simspson's Method when the relative error is less than 1 * 10^-6
public static double SimpsonError(double a, double b, double s, int n)
{
double futureVal;
double absError = 1.0;
double finalValueOfN;
double numberOfIterations = 0.0;
double currentVal = SimpsonsRule(a,b,s,n);
while (absError / currentVal > 0.000001) {
n = 2*n;
futureVal = SimpsonsRule(a,b,s,n);
absError = Math.abs(futureVal - currentVal) / 15;
currentVal = futureVal;
}
// Find the number of iterations. N starts at 8 and doubles
// every iteration.
finalValueOfN = n / 8;
while (finalValueOfN % 2 == 0) {
finalValueOfN = finalValueOfN / 2;
numberOfIterations++;
}
System.out.println("The number of iterations is "
+ numberOfIterations + ".");
return currentVal;
}
// Returns an approximate sum of Zeta(s) through Simpson's rule.
public static double getSimpsonSum(double s) {
double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*
(gamma(1+s)));
System.out.println("Did Simpson's Method.");
return constant*SimpsonError(0, 100, s, 8);
}
}
Would I have to change all of my double calculations to BigDecimal calculations in order to fix this?
Nope. All you would need to do is to catch and handle the NumberFormatException appropriately. Or, test for NaN and Inf before attempting to convert the double.
In this case, you are only using BigDecimal for formatting in "engineering" syntax. So another alternative would be to do the formatting directly. (Though I haven't found a simple way to do that yet.)
This error occurs with you because BigDecimal.valueOf(value) does not accept "NaN" "Not a Number" as parameter and the following expression will return NaN
Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)
this Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2)) will evaluate -0.0
and this function gamma(1-s) will evaluate "Infinity"
So -0.0 * Infinity equal NaN in java
please see this to know When can Java produce a NaN.
When can Java produce a NaN?
I know how to impelment pow(double x, int y)
public class Solution {
public double myPow(double x, int n) {
if (n == 0)
return 1;
if (n % 2 == 0) {
return myPow(x * x, n / 2);
} else {
if (n > 0)
return x * myPow(x, n - 1);
else
return 1 / x * myPow(x, n + 1);
}
}
}
But how to make it handle double y?
Exponentiation with non-integer values is done mathematically with infinite series:
See here under "Exponential Series Expansion" and "Exponential Theorem"
Basically, you'll use a known infinite series of terms, and calculate a number of them that satisfies your numerical precision requirements.
If i recall correctly you need to write a series expansion for log (natural logarithm) and exp (exponent).Sincelog(x^y) = y*log(x) andexp(log(x)) = xyou can evaluate the result. I think I used the Taylor series for this.wikipedia
In this code:
public class PiCalc {
public static void main(String[] args) {
double pi = 1.0;
int n = 3;
int denominator = 3;
while (n<10) {
if (n%2 == 0) {
pi += 1/denominator;
}
else {
pi -= 1/denominator;
}
n++;
denominator += 2;
}
System.out.println(4*pi + "," + n + "," + denominator);
}
}
The output is:
4.0,10,17
So, variables n and denominator are updating as I want, but pi isn't. Can anyone tell me why?
read up on "int division" as that's what you're doing:
1 / (some int bigger than 1) returns 0
A statement where an int divides an int must return an int, so it rounds towards 0 always.
Change it to
1.0 / denominator
or
(double) 1 / denominator
so that you're doing double division.
For best practices' sake, you should not be casting denominator from int to double constantly--you are only using it as a double, so it should be a double typed variable. Casting ints to doubles (or back) is not free. Making denominator into a double will be faster and simpler to understand:
public class PiCalc {
public static void main(String[] args) {
double pi = 1.0;
double denominator = 3.0;
int n = 3;
while (n<10) {
if (n%2 == 0) {
pi += 1.0/denominator;
}
else {
pi -= 1.0/denominator;
}
n++;
denominator += 2.0;
}
System.out.println(4*pi + "," + n + "," + denominator);
}
}
For that matter, if you are going to make the loop run for more than a few cycles (to get a really accurate pi), you could further increase performance by ditching the if:
public class PiCalc {
public static void main(String[] args) {
double pi = 1.0;
double denominator = 3.0;
int n = 3;
while (n<10000) /* get a really accurate PI */ {
pi -= 1.0/denominator;
n++;
denominator += 2.0;
pi += 1.0/denominator;
n++;
denominator += 2.0;
}
System.out.println(4*pi + "," + n + "," + denominator);
}
}
1/denominator is always going to equate to 0 because both are type int - like somebody else mentioned read up on int division. You probably want to cast both to double to match your pi variable. So I would change the if block to something like this.
if (n%2 == 0) {
pi += 1d/(double)denominator;
} else {
pi -= 1d/(double)denominator;
}
Please help. I've been working on this non stop and can't get it right. The issue I'm having is that the output I'm getting for the inverse is always 1.
This is the code that I have (it computes GCD and trying to modify so it also computes a^-1):
import java.util.Scanner;
public class scratchwork
{
public static void main (String[] args)
{
Scanner keyboard = new Scanner(System.in);
long n, a, on, oa;
long gcd = 0;
System.out.println("Please enter your dividend:");
n= keyboard.nextLong();
System.out.println("Please enter your divisor:");
a= keyboard.nextLong();
on= n;
oa= a;
while (a!= 0)
{gcd=a;
a= n% a;
n= gcd;
}
System.out.println("Results: GCD(" + odd + ", " + odr + ") = " + gcd);
long vX; vS; vT; vY; q; vR; vZ; m; b;
vX = n; vY=a;
vS = 0; vT = 1; m=0; b=0;
while (a != 0)
{
m=vT;;
b=vX;
q = n / a;
vR = vS - q*vT;
tZ = n - q*a;
vS = vT; n = da;
vT = tY; dY = vZ;
}
if (d>1) System.out.println("Inverse does not exist.");
else System.out.println("The inverse of "+oa+" mod "+on+" is "+vT);
}
}
The code you've posted does not declare most of the variables it uses and thus dues not compile. Most importantly, the variable v it uses to output the result is neither defined nor assigned to anywhere in the posted code - whatever it contains has nothing to do with the calculation.
Can we see the variables declaration? If you mix integer with double, your numbers can be rounded. Anyway, if you only want the inverse, juste use Math.pow(a, -1);
Also, in the second loop, you never set "a" so it will loop forever:
while (a != 0)
{
m=vT;;
b=vX;
q = n / a;
vR = vS - q*vT;
tZ = n - q*a;
vS = vT; n = da;
vT = tY; dY = vZ;
}
#Justin,
Thanks. I was able to figure out how to print out the variables in each loop. I basically had to put my loop up with the GCD loop...that was it. 2 weeks worth of work and I had just to move where the loop was.
It works! I'm sorry but I'm doing a happy dance over here.
Here's a solution in Python that should be easily translatable into Java:
def euclid(x, y):
"""Given x < y, find a and b such that a * x + b * y = g where, g is the
gcd of x and y. Returns (a,b,g)."""
assert x < y
assert x >= 0
assert y > 0
if x == 0:
# gcd(0,y) = y
return (0, 1, y)
else:
# Write y as y = dx + r
d = y/x
r = y - d*x
# Compute for the simpler problem.
(a, b, g) = euclid(r, x)
# Then ar + bx = g -->
# a(y-dx) + bx = g -->
# ay - adx + bx = g -->
# (b-ad)x + ay = g
return (b-a*d, a, g)
def modinv(x, n):
(a, b, g) = euclid(x%n, n)
assert g == 1
# a * x + b * n = 1 therefore
# a * x = 1 (mod n)
return a%n
It uses the stack, but Euclid's algorithm takes O(log n) steps so you won't have a stack overflow unless your numbers are astronomically high. One could also translate it into a non-recursive version with some effort.