asdfghjkl asdfghjkl - 14 days ago 7
Java Question

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!

Answer
  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;
    }
Comments