Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating sin(x) w/oMath and using loops only in java

I've got to calculate Math.sin(x) using the Taylor Series:

n

∑ (-1)^i* (x^(2i+1) / (2i+1)!) for n → ∞

i=0

Therefore, I am only allowed to use loops (no recursion) and I may not use the Math class. This is how far I've come:

public double sinLoops(double x) {
        int potenz1;
        double potenz2 = x;
        double fac = 1;
        double result = 0;

        do {
            if ((i % 2) == 0) {
                potenz1 = 1;
            } else {
                potenz1 = (-1);
            }

            for (int counter = 1; counter < (2 * i + 1); counter++) {
                potenz2 *= x;
            }
            for (int counter2 = (2 * i + 1); counter2 >= 1; counter2--) {
                fac *= counter2;
            }   
            result += potenz1 * potenz2 / fac;
            i++;
        } while (result > 0.0000001 || result < -0.0000001);
        return result;
    }

However, I think my break condition isn't quite correct (-1*10^-7 or 1*10^-7),the returned result is NaN. I've already looked it up, but I am kinda overchallenged right now, so I'm hoping someone can help me with this. :)

Thanks in advance!

like image 937
asdfghjkl Avatar asked Nov 20 '16 00:11

asdfghjkl


2 Answers

  1. You did not initialize i.
  2. You checked the final conditional against result rather than that taylor element of the sum.
  3. You left the potenz2 and fac elements to keep spiral out of control rather than reset them for each new element in the series.
  4. Eventually they would reach infinity and infinity, divide those and get NaN. NaN added to the running result is NaN and that actually returns true for the conditional and exited the loop (NaN has odd effects with conditionals).

Here's the working code with comments at the problems.

    public double sinLoops(double x) {
        int i = 0; //this didn't exist.
        double result = 0;
        double seriesElement; //You need the individual taylor series element.
        do {
            double potenz2 = x; //these need to be reset each time.
            double fac = 1; //if not they overflow and infinity/infinity is NaN and it exits.
            int potenz1 = ((i & 1) == 1) ? -1 : 1; //this is just short hand.
            for (int counter = 1; counter < (2 * i + 1); counter++) {
                potenz2 *= x;
            }
            for (int counter2 = (2 * i + 1); counter2 >= 1; counter2--) {
                fac *= counter2; //we could actually keep the last iteration and do 2*(i-1)+1 to 2*i+1 each new i.
            }
            seriesElement = potenz1 * potenz2 / fac; //we need to save the value here.

            result += seriesElement; //we are summing them in the results.
            i++;

        } while (seriesElement > 0.0000001 || seriesElement < -0.0000001); //We check this conditional against the series element, *NOT THE RESULT*
        return result;
    }

In case anybody needs this somehow for some kind of production work with speed being critical (and a less wrong answer, though really in that case use Math), rather than the "can somebody do my homework for me" type here's the optimized code:

public double sinLoops(double x) {
        double result = 0, powerx = -1, fac = 1;
        int i = 0, n, m = 0;
        while (true) {
            n = m;
            m = (i++*2) + 1;
            powerx *= -1;
            while (n < m) {
                powerx *= x;
                fac *= ++n;
            }
            if ((Double.isInfinite(fac)) || (Double.isInfinite(powerx))) break;
            result += powerx / fac;
        }
        return result;
    }
like image 170
Tatarize Avatar answered Sep 19 '22 10:09

Tatarize


You are not modifying the value of result variable :)

Also variable i is undeclared. Really, would be much easier if you posted a working code sample.

Once that is fixed, you should be comparing the change between previous calculation and the latest to your delta value (0.000001), not result itself. Your loop needs to end once series converges to the desired precision, not when the calculated value is really small.

You also have a couple of mistakes like off-by-one error in loop counters and not re-initializing accumulating variables between loop iterations. It is easily analyzed by running through the case of arguments of 0 and Pi.

like image 34
MK. Avatar answered Sep 20 '22 10:09

MK.