2016-11-20 19 views
6

Muszę obliczyć Math.sin (x) za pomocą Taylor Seria:Obliczanie sin (x) w/oMath i za pomocą pętli tylko w Javie

n

Σ (-1)^i * (x^(2^+ 1)/(2^+ 1)!) dla n → ∞

i = 0

Dlatego m używać tylko pętle (nie rekurencji) i Nie mogę używać klasy Math. To jak daleko doszedłem:

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

Myślę jednak, że mój stan przerwa nie jest całkiem poprawne (-1 * 10^-7 lub 1 * 10^-7), zwracany jest wynik NaN. Już to sprawdziłem, ale jestem trochę przesadzona, więc mam nadzieję, że ktoś mi w tym pomoże. :)

Z góry dziękuję!

+4

Masz nieskończoną pętlę, ponieważ twój stan zachowania nie jest taki, jak chcesz. Prawdopodobnie próbujesz ponownie użyć zmiennych dla 2 różnych celów i nie. Utwórz zmienną delta, w której zapisujesz zmianę dokonaną w tej interakcji i przetestuj wartość detla w warunku. – HopefullyHelpful

Odpowiedz

5
  1. Nie zainicjalizowałeś.
  2. Sprawdziłeś ostateczny warunek względem wyniku, a nie ten element taylor sumy.
  3. Zostawiliście elementy potenz2 i fac, aby wymknąć się spod kontroli zamiast resetować je dla każdego nowego elementu w serii.
  4. W końcu osiągną nieskończoność i nieskończoność, podzielą je i zdobędą NaN. NaN dodany do bieżącego wyniku to NaN, który faktycznie zwraca wartość true dla warunkowej i zakończonej pętli (NaN ma efekty nieparzyste z warunkami warunkowymi).

Oto działający kod z komentarzami na temat problemów.

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

W przypadku, ktoś musi to jakoś do jakiejś pracy produkcyjnej z prędkością będącego krytyczna (i mniej złą odpowiedź, choć tak naprawdę w tym przypadku użyć Math), raczej niż „może ktoś odrabiam lekcje dla mnie "wpisz tutaj zoptymalizowany kod:

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; 
    } 
+0

Nie zrobiłem tego wykonaj jedną z oczywistych ulepszeń, takich jak użycie jednej pętli licznika zamiast 2 (podpowiedź: robisz pętlę tyle razy ile razy!) lub wykonaj oczywiste ulepszenia utrzymując wartości potenz2 i fac i po prostu zapętlaj dodatkowe i razy w jednym Pętla, która również pozwoli ci pozbyć się bzdur potenz1 i po prostu pomnożyć sumę przez -1 za każdym razem (to by się poprawnie ułożyło). – Tatarize

+0

Naprawiono problem z kontrolą parzystości. – Tatarize

1

Nie modyfikujemy wartość zmiennej wynikowej :)

Również zmienna jest nielegalna. Naprawdę byłoby znacznie łatwiej, gdyby opublikowano działający przykładowy kod.

Po ustaleniu, powinieneś porównywać zmianę pomiędzy poprzednim obliczeniem a najnowszym z wartością delta (0,000001), a nie sam wynik. Twoja pętla musi się kończyć, gdy seria zbiegnie się do pożądanej precyzji, a nie wtedy, gdy obliczona wartość jest naprawdę mała.

Masz również kilka błędów, takich jak błąd "jeden po drugim" w licznikach pętli i nie reinicjalizuj akumulujących zmiennych między iteracjami pętli. Można go łatwo przeanalizować, przechodząc przez przypadek argumentów 0 i Pi.

+0

Och, przepraszam: D Zmienna "ergebnis" jest zmienną "wynik", będę to zmieniać bezpośrednio - był to błąd ortograficzny, który popełniłem podczas tłumaczenia wszystkich zmiennych z języka niemieckiego na angielski :) – asdfghjkl

1

Interesujące pytanie. Podobnie jak Tataryzacja, mam nadzieję, że to nie jest unikanie zadań domowych.

Ten kod wygląda na zapowiedź liczby terminów potrzebnych do uzyskania bezwzględnej precyzji +/- 0,000 000 1 w wyniku dla wszystkich kątów 0 - 90 stopni.

Najwyższy poziom mocy powoduje różnicę x^k/k! do wyniku. Więc

  x^k/k! < 1/10^7 

Tutaj x jest w radianach więc największą wartość X ~ 1,57 radów. Oznacza to, że tylko seria do mocy 13 daje końcowy okres mniejszy niż 0.000 000 1.

Niestety mój komputer ma zaawansowany wiek (32-bitowy) i każdą próbę obliczenia 13! powoduje przepełnienie. Więc dostosować Horner method trochę, może trochę utraty wydajności, ale unikając silni przepełnienia i umożliwia wstrzymanie jeśli kąt jest niewielka lub jeśli odpowiednia precyzja jest zdobyte przed mocą 13.

Sin x = x - x^2(x/3! - x^2(x/5! - x^2(x/7! - . . . - x^2(x/(m-1)!- x^2(x/m!) 

gdzie m jest najwyższa moc potrzebna do żądana absolutna precyzja.

Sin x = x + Sum { iTerm(i) * x^2/(i * (i-1)) } 

gdzie

iTerm(0) = x and iTerm(n) = - x^2 * iTerm(n-1)/(i*(i-1) 

PS - Dlaczego nie możemy użyć formatowania Math poza Matematyki Stos Exchange? To spowodowałoby, że równania zapisu byłyby o wiele jaśniejsze.

public class TrigByPoly 
{ 
    // No constructor used. 

    public static void main(String[] args) 
    { 
     double x0 = 0, 
       x1 = Math.PI/12, 
       x2 = Math.PI/6, 
       x3 = Math.PI/4, 
       x4 = Math.PI/3, 
       x5 = Math.PI/2; 

     double sinx0 = SinByPoly(x0), 
       sinx1 = SinByPoly(x1), 
       sinx2 = SinByPoly(x2), 
       sinx3 = SinByPoly(x3), 
       sinx4 = SinByPoly(x4), 
       sinx5 = SinByPoly(x5); 

     System.out.println("Sin(0) to 7 decimal places is : " + sinx0); 
     System.out.println("Sin(15) to 7 decimal places is : " + sinx1); 
     System.out.println("Sin(30) to 7 decimal places is : " + sinx2); 
     System.out.println("Sin(45) to 7 decimal places is : " + sinx3); 
     System.out.println("Sin(60) to 7 decimal places is : " + sinx4); 
     System.out.println("Sin(90) to 7 decimal places is : " + sinx5); 
    } 

    public static double SinByPoly(double x) 
    { 
     int i = 0; // Polynomial order indicator. 

     double x2 = x * x, 
       iTerm, 
       sinx = 0; 

     if (x < 0.0084) // Limiting angle for Sinx = x to 10^-7 precision. 
      sinx = x; 
     else 
     { 
      sinx = x; 
      iTerm = sinx; 
      i = 3; 
      do 
      { 
       iTerm = - x2 * iTerm/(i * (i - 1)); 
       sinx += iTerm; 
       i = i + 2; 
      } while (i < 14 && (iTerm > 0.0000001 || -iTerm > 0.0000001)); 
     } 
     return sinx; 
    } 
} 

OUTPUT 
====== 

Sin(0) to an absolute precision of 1.0E-7 is : 0.0 
Sin(15) to an absolute precision of 1.0E-7 is : 0.2588190618109834 
Sin(30) to an absolute precision of 1.0E-7 is : 0.4999999918690232 
Sin(45) to an absolute precision of 1.0E-7 is : 0.7071067829368671 
Sin(60) to an absolute precision of 1.0E-7 is : 0.8660254450997811 
Sin(75) to an absolute precision of 1.0E-7 is : 0.9659258210120795 
Sin(90) to an absolute precision of 1.0E-7 is : 0.999999943741051 
+0

Zacząłem używać lateksu w sieci tu i tam, aby uzyskać plik graficzny, który go osadza, ponieważ ten głupi nie może wykonywać równań matematycznych. – Tatarize

+0

The StackOverflow DBA mówi tutaj [link] http://meta.stackoverflow.com/questions/252282/theres-seriously-no-reason-why-latex-markup-via-mathjax-shouldnt-be-enabled-on it's going spowalnia ładowanie WSZYSTKICH stron SO, jeśli jest dodana. Ale być może jest jakiś sposób dynamicznego włączenia go lub jego lżejszej wersji. . .? – Trunk