Funkcja licząca sinusa

Funkcja licząca sinusa
M7
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 5 lat
  • Postów:3
0

Dzień dobry.
Chcę napisać funkcję liczącą przybliżenie sinusa za pomocą wzoru Taylora z zadaną dokładnością. Napisałem na razie coś takiego:

Kopiuj
double sinus(double x)
{
    double wynik=0;
    double y=x;
    double z=2;
    
    for(int n=0; n<10; n++)
    {
        wynik+=y;
        y*=-1;
        y*=x;
        y*=x;
        y=y/(z++);
        y=y/(z++);
    }
    
    return wynik;
}

i mam dwa pytania: czy da się jakoś "ładniej" zapisać środek pętli tzn. aby tyle nie mnożyć i dzielić,
a drugie to jak ustawić zadać dokładność liczenia? Nie umiałem tego zrobić stąd pętla for na 10 powtórzeń.

edytowany 1x, ostatnio: flowCRANE
lion137
A to w ogóle Ci działa, daje dobre wyniki?
M7
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 5 lat
  • Postów:3
0

Tak, wynik jest dobry. Zgadza się z tym co w wolframie po 3-4 powtórzeniach pętli

lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Postów:4944
0

Tu https://4programmers.net/Forum/C_i_C++/321157-wzor_maclaurina_dla_sin?p=1558555#id1558555 jest rozwinięcie w szereg MacLaurina. Dokładność zależna od ilości iteracji. A jak ocenić dokładność absolutną, sam chciałbym wiedzieć!


M7
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 5 lat
  • Postów:3
0

Dziękuję za odpowiedź jednak nie mogę w swoim rozwiązaniu użyć żadnej funkcji bibliotecznej, a algorytm nie może liczyć silni...

lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Postów:4944
0

To nie wiem, bo w rozwinięciu w szereg Taylora/MacLaurina jest silnia, poza tym nie używam funkcji bibliotecznych.


mwl4
  • Rejestracja:około 12 lat
  • Ostatnio:29 dni
  • Lokalizacja:Wrocław
  • Postów:399
0

W tym przypadku wydaje mi się, że jedyne co możesz zrobić to:

Kopiuj
double sinus( double x )
{
    double wynik = 0;
    double y = x;
    double z = 2;
 
    for ( int n = 0; n < 10; ++n )
    {
        wynik += y;
        y *= -x * x;
        y = y / ( z++ );
        y = y / ( z++ );
    }
 
    return wynik;
}

Co do drugiego pytania to możesz przesłać w drugim parametrze (który jest ustawiony domyślnie na 10) tę precyzję, o tak:

Kopiuj
double sinus( double x, int precision = 10 )
// ...
    for ( int n = 0; n < precision; ++n ) // tutaj nie jestem pewien, czy precyzja zależy od liczby iteracji - możliwe, że nie.

Cały kod z trzema testami: https://ideone.com/OW78Ci


Asm/C/C++
edytowany 4x, ostatnio: mwl4
enedil
Ale to są bzdury, przecież precyzja oznacza odchylenie od prawidłowej wartości, ew. odchylenie od przedniego przybliżenia, nie zaś liczbę iteracji metody.
mwl4
@enedil: Nie mówię nie, ale dostarcz jakieś źródło, które temu przeczy. Wtedy poprawię bo teraz wydaje mi się, że precyzja właśnie od liczby iteracji jest zależna.
enedil
Jest zależna, ale nie wiesz w jaki sposób i tego nie kontrolujesz. Skąd wiesz czy dodanie kolejnej wartości są wynik, który zmniejszy błąd 10 razy?
mwl4
@enedil: To zaproponuj inną nazwę dla parametru albo inne rozwiązanie problemu dokładności.
lion137
Co można zakodować, to sprawdzanie czy dwa wyrazy są mniejsze od jakiegoś epsilon. Niestety, tak jak ja to napisałem, to nie wiem, jak zmienić.
MY
  • Rejestracja:prawie 10 lat
  • Ostatnio:3 dni
  • Postów:1083
0

Liczenie przy rozwinięciu w szereg z zadaną dokładnością eps odbywa się w ten sposób, że kończymy obliczanie w przypadku, gdy moduł n-tego element rozwinięcia jest mniejszy od naszego zadanego eps. Nic trudnego. W pseudokodzie będzie to coś takiego:

Kopiuj
double sinus(double x, double eps)
{
  int i;
  double temp,value;

  value = x;  // wynik zwracany
  i = 1;    // licznik petli
  temp = x; // i-ty element szeregu, w pierwszym przylizeniu to po prostu x
 
  while (fabs(temp) > eps)
  {
    temp = ....; // tu obliczamy sobie i-ty element szeregu
    value = value + temp;
    ++i;
  }
  return value;
}
edytowany 1x, ostatnio: Mr.YaHooo
lion137
No, tak, ale z tego co sobie przypominam z wykładów, rozwinięcie ma resztę, i oszacowanie tej reszty daje nam dokładność; plus jeszcze dokładność liczb zmiennoprzecinkowych. Jak się dostanę do mojego kompa (miałem mały fail), to zobaczę co mówią książki do metod numerycznych. Ale generalnie, racja, to będzie w miarę dobre przybliżenie.
MY
@lion137: tak masz 100% rację. Istnieją wzory pozwalające na dokładne obliczenie reszty. Jednak niestety w tej chwili ich nie pamiętam. Z drugiej strony wiadomo, że z powodu silni w mianowniku całość szybko maleje. U mnie na zajęciach numerycznych w ten sposób liczyliśmy sinusy. Przy epsilonie rzędu 10e-6 można spokojnie przyjąć taki sposób za dokładny do naszych potrzeb.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.