Clarification on "Calculate e^x without inbuilt functions in Java" - java

The question was basically to calculate e^x without inbuilt functions in Java.
The sequence to code was e^x = 1+x+x2/2!+x3/3!+x4/4!+ ...
Here was my attempt at the question:
public static void myexp(double x, double i){
double j = 1.0;
double sum = x;
while (j <= i){
j = j + 1;
sum = sum + (sum * (x / (j)));
System.out.println(sum + 1 + x);
}
}
public static void main(String[] args) {
double x = 1;
double i = 5.0;
myexp(x, i);
}
Now it wasn't working, and eventually I gave in and looked up what a model answer should look like (I know, I know). Here is what it is (in the style of my code):
public static void myexp(double x, double i){
double j = 1.0;
double sum = x;
double result = 1.0;
while (j <= i){
j = j + 1;
sum = sum * (x / (j));
result = result + sum;
System.out.println(result + x);
}
}
Now the difference is the inclusion of the 'results' variable, which delineates the summation of the sequence. However, I thought I had incorporated that when I wrote
"sum = sum+(sum*(x/(j)));".
But the machine recognises one style and not the other. What gives?

In each iteration you are supposed to add to the total sum the term
sum * x / j
where sum is the term added in the previous iteration.
This means you must store the term added in the previous iteration in a separate variable.
If you use the same variable for the total result (which is supposed to be the sum of all the terms of all iterations) and for the term of the current iteration (sum), you get an entirely different result.
In other words
sum = sum + (sum * (x / (j)));
is not equivalent to
sum = sum * (x / (j));
result = result + sum;
since the value of sum depends on the previous value of sum, and therefore you can't eliminate that variable.

Related

Why is my trapezoid rule implementation not producing expected results?

I have implemented a function to find the trapezoid rule of a given function, the function produces poor results for
.
When I try to calculate the trapezoid rule with n < 8 it produces a value much larger than the actual area, which is unexpected, I have graphed f(x) and drawn how I believe the first few numbers of trapezoids would look, and they all should be producing less than the target area.
However, as n increases, the error becomes lower and lower and at n = 10000000 it is within a 0.001 of the solution.
private interface MathFunc {
double apply(double value);
}
private static final double A = 1;
private static final double B = 9;
public static void main(String args[]) {
MathFunc func = (x) -> Math.log(x) / Math.log(2);
double realValue = 16.98776493946568;
for(int i = 1; i <= 8; i*=2) {
double value = trapezoidRule(A, B, func, i);
System.out.println(i + " Trapezoid Summation for f(x): " + value);
double absError = Math.abs(value - realValue);
System.out.println("Abs Error: " + absError);
System.out.println("% Error: " + (absError/realValue)*100);
System.out.println();
}
}
static double trapezoidRule(double a, double b, MathFunc f, double n) {
double deltaX = (b-a)/n;
double i = 0;
double sum = 0.0;
while( i++ <= n ) {
if(i == 0 || i == n) {
sum += f.apply(a + (i*deltaX));
} else {
sum += 2 * f.apply(a + (i*deltaX));
}
}
return (deltaX * sum) / 2.0;
}
If you step through trapezoidRule for n = 1 in a debugger, you'll see that the loop is executed for i=1 and i=2. Since i=2 is treated as a midpoint, it is counted twice.
Why is the loop executed for wrong values of i? The expression i++ uses the post-increment operator, which increments the variable after returning its value. You should be using a pre-increment operator ++i, or a for loop like any sane person:
for (double i = 0; i <= n; i++) {
while( i++ <= n )
Was causing an issue, as it was doing an extra iteration.
while( i++ < n )
Produces the correct values.

java Sine(x) Taylor Series

Can someone help me for geting out this code of sin(x) Tailor function to get followings:
The first 4 sin(x) Tailor series.
To calculating the sin function using the sum-formel
How to write a method public static double MySinApproximate( double x)?
That is what i get so far, and it has to be in this way!!
import java.lang.Math;
public class mysin {
public static void main(String[] args){
double x= Math.PI;
System.out.println( MySin(x) + "\t \t" + Math.sin(x) + "\n" );
}
public static double MySin(double x){
double sumNeu, sumOld, sum;
int i = 1;
sum = sumNeu = x; // This should calculating the first term Value
do //the loop do will calculating the Tailor Series
{
sumOld = sumNeu;
i++; sum = + sum * x * x / i;
i++; sum = sum / i;
sumNeu = sumOld + sum;
}
while( sumNeu != sumOld);
return sumNeu;
}
} // 11.548739357257745 1.2246467991473532E-16 (as output)
Your loop isn't calculating the Taylor series correctly. (This is really a Maclaurin series, which is the special case of a Taylor series with a = 0.) For the sine function, the terms need to be added and subtracted in an alternating fashion.
sin(x) = x - x3/3! + x5/5! - ...
Your method only adds the terms.
sin(x) = x + x3/3! + x5/5! + ...
Flip the sign of sum on each iteration, by adding the designated line:
do // The loop will calculate the Taylor Series
{
sumOld = sumNeu;
i++; sum = + sum * x * x / i;
i++; sum = sum / i;
sum = -sum; // Add this line!
sumNeu = sumOld + sum;
}
With this change I get a result that is very close:
2.3489882528577605E-16 1.2246467991473532E-16
Due to the inherent inaccuracies of floating-point math in Java (and IEEE in general), this is likely as close as you'll get by writing your own sine method.
I tested an additional case of π/2:
System.out.println( MySin(x/2) + "\t \t" + Math.sin(x/2) + "\n" );
Again, it's close:
1.0000000000000002 1.0
1.I want to write all again like that -
2.I try to writing the first 4 series from sine Taylor and the proximity all together but anyhow doesn't work correctly -
3.i get this output
0.0 0.8414709848078965
0.8414709848078965 0.9092974268256817
0.8414709848078965 0.1411200080598672
0.9092974268256817 -0.7568024953079282
4.How can i get the same accuracy
1.0000000000000002 1.0
and the series of sine(x)?
public class MySin {
public static void main(String[] args){
double y = 0;
y = 4;
for (int i = 1; i<= y; i++){
System.out.println( MySin(i/2) + "\t \t" + Math.sin(i) + "\n" );
}
}
public static double MySin(double x){
double sumNew, sumOld, sum;
int i = 1;
sum = sumNew = x; // This should calculating the first term Value
do //the loop do will calculating the Tailor Series
{
sumOld = sumNew;
i++; sum = - sum * x * x / i; // i did change the sign to -
i++; sum = sum / i;
sum = - sum; // so i don't need this line anymore
sumNew = sumOld + sum;
}
while( sumNew != sumOld);
return sumNew;
}
public static double MySineProximity ( double x) {
while ( x <= ( Math.PI /2 ) )
{
x = 0;
}
return MySin (x);
}
}

Riemann Zeta Function in Java - Infinite Recursion with Functional Form

Note: Updated on 06/17/2015. Of course this is possible. See the solution below.
Even if anyone copies and pastes this code, you still have a lot of cleanup to do. Also note that you will have problems inside the critical strip from Re(s) = 0 to Re(s) = 1 :). But this is a good start.
import java.util.Scanner;
public class NewTest{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
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 <= 0)
System.out.println("Value for the Zeta Function = " + riemannFuncForm(s));
else if (s == 1)
System.out.println("The zeta funxtion is undefined for Re(s) = 1.");
else if(s >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getNewSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the 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;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
//New Form
// zeta(s) = 2^(-1+2 s)/((-2+2^s) Gamma(1+s)) integral_0^infinity t^s sech^2(t) dt for Re(s)>-1
public static double Integrate(double start, double end) {
double currentIntegralValue = 0;
double dx = 0.0001d; // The size of delta x in the approximation
double x = start; // A = starting point of integration, B = ending point of integration.
// Ending conditions for the while loop
// Condition #1: The value of b - x(i) is less than delta(x).
// This would throw an out of bounds exception.
// Condition #2: The value of b - x(i) is greater than 0 (Since you start at A and split the integral
// up into "infinitesimally small" chunks up until you reach delta(x)*n.
while (Math.abs(end - x) >= dx && (end - x) > 0) {
currentIntegralValue += function(x) * dx; // Use the (Riemann) rectangle sums at xi to compute width * height
x += dx; // Add these sums together
}
return currentIntegralValue;
}
private static double function(double s) {
double sech = 1 / Math.cosh(s); // Hyperbolic cosecant
double squared = Math.pow(sech, 2);
return ((Math.pow(s, 0.5)) * squared);
}
public static double getNewSum(double s){
double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*(gamma(1+s)));
return constant*Integrate(0, 1000);
}
// Gamma Function - 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;
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;
}
//Binomial Co-efficient - NOT CURRENTLY USING
/*
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
} */
// Riemann's Functional Equation
// Tried this initially and utterly failed.
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);
double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else
return Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)*standardZeta(1-s);
}
}
Ok well we've figured out that for this particular function, since this form of it isn't actually a infinite series, we cannot approximate using recursion. However the infinite sum of the Riemann Zeta series (1\(n^s) where n = 1 to infinity) could be solved through this method.
Additionally this method could be used to find any infinite series' sum, product, or limit.
If you execute the code your currently have, you'll get infinite recursion as 1-(1-s) = s (e.g. 1-s = t, 1-t = s so you'll just switch back and forth between two values of s infinitely).
Below I talk about the sum of series. It appears you are calculating the product of the series instead. The concepts below should work for either.
Besides this, the Riemann Zeta Function is an infinite series. This means that it only has a limit, and will never reach a true sum (in finite time) and so you cannot get an exact answer through recursion.
However, if you introduce a "threshold" factor, you can get an approximation that is as good as you like. The sum will increase/decrease as each term is added. Once the sum stabilizes, you can quit out of recursion and return your approximate sum. "Stabilized" is defined using your threshold factor. Once the sum varies by an amount less than this threshold factor (which you have defined), your sum has stabilized.
A smaller threshold leads to a better approximation, but also longer computation time.
(Note: this method only works if your series converges, if it has a chance of not converging, you might also want to build in a maxSteps variable to cease execution if the series hasn't converged to your satisfaction after maxSteps steps of recursion.)
Here's an example implementation, note that you'll have to play with threshold and maxSteps to determine appropriate values:
/* Riemann's Functional Equation
* threshold - if two terms differ by less than this absolute amount, return
* currSteps/maxSteps - if currSteps becomes maxSteps, give up on convergence and return
* currVal - the current product, used to determine threshold case (start at 1)
*/
public static double riemannFuncForm(double s, double threshold, int currSteps, int maxSteps, double currVal) {
double nextVal = currVal*(Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else if (Math.abs(currVal-nextVal) < threshold) //When a term will change the current answer by less than threshold
return nextVal; //Could also do currVal here (shouldn't matter much as they differ by < threshold)
else if (currSteps == maxSteps)//When you've taken the max allowed steps
return nextVal; //You might want to print something here so you know you didn't converge
else //Otherwise just keep recursing
return riemannFuncForm(1-s, threshold, ++currSteps, maxSteps, nextVal);
}
}
This is not possible.
The functional form of the Riemann Zeta Function is --
zeta(s) = 2^s pi^(-1+s) Gamma(1-s) sin((pi s)/2) zeta(1-s)
This is different from the standard equation in which an infinite sum is measured from 1/k^s for all k = 1 to k = infinity. It is possible to write this as something similar to --
// Standard form the 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;
}
The same logic doesn't apply to the functional equation (it isn't a direct sum, it is a mathematical relationship). This would require a rather clever way of designing a program to calculate negative values of Zeta(s)!
The literal interpretation of this Java code is ---
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else
System.out.println("Value of next value is " + nextVal(1-s));
return currentVal;//*nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
public static double getRiemannSum(double s) {
return riemannFuncForm(s);
}
Testing on three or four values shows that this doesn't work. If you write something similar to --
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else //Otherwise just keep recursing
return currentVal * nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
I was misinterpretation how to do this through mathematics. I will have to use a different approximation of the zeta function for values less than 2.
I think I need to use a different form of the zeta function. When I run the entire program ---
import java.util.Scanner;
public class Test4{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
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 >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getRiemannSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the 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;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
// Riemann's Functional Equation
public static double riemannFuncForm(double s, double threshold, double currSteps, int maxSteps) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
//double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
//double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else if (s == 0.0)
return -0.5;
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
else if (currSteps == maxSteps) {//The recursion will stop if you meet the max steps
System.out.println("The series did not converge.");
return term;
}
else //Otherwise just keep recursing
return term*riemannFuncForm(1-s, threshold, ++currSteps, maxSteps);
}
public static double getRiemannSum(double s) {
double threshold = 0.00001;
double currSteps = 1;
int maxSteps = 1000;
return riemannFuncForm(s, threshold, currSteps, maxSteps);
}
// Gamma Function - 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;
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;
}
//Binomial Co-efficient
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
}
}
I notice that plugging in zeta(-1) returns -
Enter the value of s inside the Riemann Zeta Function: -1
The number of steps is 1.0
Value for the Zeta Function = -0.0506605918211689
Total time taken is 0.0 seconds.
I knew that this value was -1/12. I checked some other values with wolfram alpha and observed that --
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
Returns the correct value. It is just that I am multiplying this value every time by zeta(1-s). In the case of Zeta(1/2), this will always multiply the result by 0.99999999.
Enter the value of s inside the Riemann Zeta Function: 0.5
The series did not converge.
Value for the Zeta Function = 0.999999999999889
Total time taken is 0.006 seconds.
I am going to see if I can replace the part for --
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
This difference is the error between two terms in the summation. I may not be thinking about this correctly, it is 1:16am right now. Let me see if I can think better tomorrow ....

How to write 1+1/2+1/3....+1/4999+1/5000 in java?

How to write 1+1/2+1/3....+1/4999+1/5000 in java?
I have tried this but didnt work.
public class Harmonic{
public static void main(String[] args){
double sum = 0;
for(int i=1; i<=5000; i++){
sum+=1/i;
}
System.out.println(sum);
}
}
Adding numbers from smallest to largest will have a lower rounding error. If you compare the result with higher precision, you can see smaller to larger is closer.
double sum = 0;
for (int i = 1; i <= 5000; i++) {
sum += 1.0 / i;
}
System.out.println("From largest to smallest " + sum);
double sum2 = 0;
for (int i = 5000; i >= 1; i--) {
sum2 += 1.0 / i;
}
System.out.println("From smallest to largest " + sum2);
BigDecimal sum3 = BigDecimal.ZERO;
for (int i = 5000; i >= 1; i--) {
sum3 = sum3.add(BigDecimal.ONE.divide(BigDecimal.valueOf(i), 30, BigDecimal.ROUND_HALF_UP));
}
System.out.println("BigDecimal " + sum3);
prints
From largest to smallest 9.094508852984404
From smallest to largest 9.09450885298443
BigDecimal 9.094508852984436967261245533401
1 is an int constant, so 1 / (any int bigger than 1) is 0. You need to specify that you want a floating point division, by using 1.0 (float):
sum+=1.0/i;
^
That's a homework, then I just help you with a tip: be careful of variable types. 1/10 is equal to 0 if we consider it as an integer.
Try this instead:
sum += 1.0 / i;
How about:
public class Harmonic{
public static void main(String[] args){
double sum = 0;
for(int i=1; i<=5000; i++){
sum+=1.0/(double)i;
}
System.out.println(sum);
}
}
After the first iteration 1/i will always be 0 since it's done in integer arithmetic. Therefore you're final answer will just be 1. Change it to 1.0/i to get double arithmetic, and keep in mind that when you're loop finishes you may have a fair amount of error due to precision loss while using doubles. You can try it out and see how accurate it is though.
because i is an int so the division will be truncated... try putting sum+ = 1/(double)i
java-8 solution for calculating Harmonic sum:
public static double harmonicSum(int n) {
return IntStream.rangeClosed(1, n)
.mapToDouble(i -> (double) 1 / i)
.sum();
}

How to re-implement sin() method in Java ? (to have results close to Math.sin() )

I know Math.sin() can work but I need to implement it myself using factorial(int) I have a factorial method already below are my sin method but I can't get the same result as Math.sin():
public static double factorial(double n) {
if (n <= 1) // base case
return 1;
else
return n * factorial(n - 1);
}
public static double sin(int n) {
double sum = 0.0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
sum += Math.pow(1, i) / factorial(2 * i + 1);
} else {
sum += Math.pow(-1, i) / factorial(2 * i + 1);
}
}
return sum;
}
You should use the Taylor series. A great tutorial here
I can see that you've tried but your sin method is incorrect
public static sin(int n) {
// angle to radians
double rad = n*1./180.*Math.PI;
// the first element of the taylor series
double sum = rad;
// add them up until a certain precision (eg. 10)
for (int i = 1; i <= PRECISION; i++) {
if (i % 2 == 0)
sum += Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
else
sum -= Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
}
return sum;
}
A working example of calculating the sin function. Sorry I've jotted it down in C++, but hope you get the picture. It's not that different :)
Your formula is wrong and you are getting a rough result of sin(1) and all you're doing by changing n is changing the accuracy of this calculation. You should look the formula up in Wikipedia and there you'll see that your n is in the wrong place and shouldn't be used as the limit of the for loop but rather in the numerator of the fraction, in the Math.pow(...) method. Check out Taylor Series
It looks like you are trying to use the taylor series expansion for sin, but have not included the term for x. Therefore, your method will always attempt to approximate sin(1) regardless of argument.
The method parameter only controls accuracy. In a good implementation, a reasonable value for that parameter is auto-detected, preventing the caller from passing to low a value, which can result in highly inaccurate results for large x. Moreover, to assist fast convergence (and prevent unnecessary loss of significance) of the series, implementations usually use that sin(x + k * 2 * PI) = sin(x) to first move x into the range [-PI, PI].
Also, your method is not very efficient, due to the repeated evaluations of factorials. (To evaluate factorial(5) you compute factorial(3), which you have already computed in the previous iteration of the for-loop).
Finally, note that your factorial implementation accepts an argument of type double, but is only correct for integers, and your sin method should probably receive the angle as double.
Sin (x) can be represented as Taylor series:
Sin (x) = (x/1!) – (x3/3!) + (x5/5!) - (x7/7!) + …
So you can write your code like this:
public static double getSine(double x) {
double result = 0;
for (int i = 0, j = 1, k = 1; i < 100; i++, j = j + 2, k = k * -1) {
result = result + ((Math.pow(x, j) / factorial (j)) * k);
}
return result;
}
Here we have run our loop only 100 times. If you want to run more than that you need to change your base equation (otherwise infinity value will occur).
I have learned a very good trick from the book “How to solve it by computer” by R.G.Dromey. He explain it like this way:
(x3/3! ) = (x X x X x)/(3 X 2 X 1) = (x2/(3 X 2)) X (x1/1!) i = 3
(x5/5! ) = (x X x X x X x X x)/(5 X 4 X 3 X 2 X 1) = (x2/(5 X 4)) X (x3/3!) i = 5
(x7/7! ) = (x X x X x X x X x X x X x)/(7 X 6 X 5 X 4 X 3 X 2 X 1) = (x2/(7 X 6)) X (x5/5!) i = 7
So the terms (x2/(3 X 2)) , (x2/(5 X 4)), (x2/(7 X 6)) can be expressed as x2/(i X (i - 1)) for i = 3,5,7,…
Therefore to generate consecutive terms of the sine series we can write:
current ith term = (x2 / ( i X (i - 1)) ) X (previous term)
The code is following:
public static double getSine(double x) {
double result = 0;
double term = x;
result = x;
for (int i = 3, j = -1; i < 100000000; i = i + 2, j = j * -1) {
term = x * x * term / (i * (i - 1));
result = result + term * j;
}
return result;
}
Note that j variable used to alternate the sign of the term .

Categories