开发者

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

开发者 https://www.devze.com 2023-03-11 15:33 出处:网络
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():

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
        retur开发者_高级运维n 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 .

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号