Wzory Taylora - arcsinx - niedokładne liczenie.

0

Mam drobny problem z niezwykle ciekawym tematem jakim jest zaprogramowanie funkcji liczącej arcsinx ze wzoru Taylora. Problemem jest tutaj, a jakże, dokładność obliczeń a mianowicie jej brak.

Użytkownik ma za zadanie wywołać funkcje, wpisać zmienną, dla której trzeba chce ją liczyć, a następnie dokładność, czyli miejsce po przecinku do którego chce liczyć, czyli do którego miejsca po przecinku wynik ma być dokładny. W przypadku tej funkcji, chciałem zastosować ten sam patent, co w przypadku innych, które już napisałem wcześniej, lecz w przypadku arcsinx wyniki są niepoprawne:

Oto kod funkcji w wersji uproszczonej:

void arcsinus(void)
{
        double x = 0.98; // nasza zmienna |x| <= 1
        double approx = 0.01; // TUTAJ SIEDZI NASZA ZMIENNA POTRZEBNA DO BADANIA DOKLADNOSCI - nalezy ja modyfikowac w celu ustalenia dokladnosci
       
       
        double temp = x;
        double final = x;
        double pre = 0;
        int n = 1;
       
        while(n < 100000)
        {
                temp *= ((x*x)*(2*n-1)*(2*n-1))/((2*n)*(2*n+1));
                final += temp;
                n++;
               
                if(  ((pre - final) > 0 ? (pre - final) : -(pre - final)) - approx < 0 )
                break;
               
                pre = final;
        }
       
        printf("\nWartosc arcsin: %.15f\n" , final);
}
       

Dzięki za pomoc.

0

A co to za metoda - podaj wzór na arcsin?

W pobliżu 1 arcsin ma dużą pochodną, więc to tam bardzo źle się oblicza...

d arcsinx/ dx = 1/sqrt(1-x^2), co dla x -> 1 daje inf, czyli śmierć matematyka.

0

Hmmmm, serce wzoru to: temp = ((xx)(2n-1)(2n-1))/((2n)(2*n+1)) wrzucone do pętli.
No dobrze, a więc:

1.Czy jest sposób by policzyć dokładnie arcsinx gdzie x -> 1, bez użycia biblioteki matematycznej?

Identyczne podejście (tylko inne wzory Taylora oczywiście) zastosowałem dla e^x i sinx. Tam problemu nie ma, dokładność jest zachowana dla dowolnego approx.

1

A sprawdzałeś czy szereg Taylora jest w ogóle zbieżny w tym zakresie? Z tego co pamiętam, to szereg Taylora jest zbieżny tylko w otoczeniu punktu x0. Jak duże jest to otoczenie to już zależy od funkcji.

1

czemu nie mogłeś zdefiniować funkcji normalnie:

double arcSinTaylor(double x, double epsilon)

Poza tym źle zaimplementowałeś wzór, nie widzę niczego w stylu: final += temp/(2*n+1);

0
MarekR22 napisał(a):

czemu nie mogłeś zdefiniować funkcji normalnie:

double arcSinTaylor(double x, double epsilon)

Nie zdefiniowałem bo jest to funkcja wyrwana z całości programu i odpowiednio przerobiona do wklejenia tutaj. Normalnie argumenty przesyłane są w inny sposób. Nie tutaj leży problem.
Jeśli chodzi o zbieżność, to w programie są funkcje, które dbają o poprawność wprowadzania danych, ot chociażby sygnalizowany jest błąd dla |x|>1.

Wracając, istnieje przecież arcsin1, jak również kalkulatory, które liczą poprawnie wartość w jedynce. Nie mówię, że robią to w tak siłowy sposób jakim się tutaj posługuje, ale jednak jakoś to robią.

Jakieś dalsze pomysły?

0

tak jak pisałem w update masz błąd w kodzie, brakuje czegoś w stylu final += temp/(2*n+1);, część współczynnika jest niezależna od poprzedniego współczynnika szeregu.
tu znajdziesz wzór bardziej przystępny niż to co daje wolframalpha.

0
Totalq napisał(a):

1.Czy jest sposób by policzyć dokładnie arcsinx gdzie x -> 1, bez użycia biblioteki matematycznej?

Identyczne podejście (tylko inne wzory Taylora oczywiście) zastosowałem dla e^x i sinx. Tam problemu nie ma, dokładność jest zachowana dla dowolnego approx.

Zwykle chyba używa się podmianki typu:

arcsin x = arctg x/\sqrt(1-x^2)

tg x = sinx/cosx, i cosx = sqrt(1 - (sinx)2), stąd ten wzór...

albo czegoś podobnego... co ma znacznie lepszą zbieżność.

0

Podobne problemy są z liczeniem całek numerycznie.
Przykładowo taka całka:

int arccos x * f(x) dx; od 0 do 1.

ten arccos ma nieskończoną pochodną w 1, więc to się łatwo posypie, gdyby podejść do tego z marszu - dokładność będzie gówniana nawet gdy użyjemy Simpsona z 10000 przedziałów!

A wystarczy podstawić: x = cost => dx = -sint, i teraz mamy:

int t sint f(cost) dt; i teraz t = 0.. pi/2;

i to pójdzie już jak rakieta - Simpson i 10 przedziałów da bardzo dobry wynik!

Można sobie to przećwiczyć, wsadzając f = 1, czyli całkujemy sam ten zasrany arccos.

1

Widzę, że kot z powodu wódki za bardzo kombinuje.
On m po prostu błąd w kodzie.
Zlituje się prezentując działający kod (działa z dokładnością double):
http://ideone.com/8Qfdbt

1 użytkowników online, w tym zalogowanych: 0, gości: 1