funkcja tablicowanie w szereg Taylora

0

Mam problem z napisaniem funkcji która przez iterację bedzię liczyła następny wyraz szeregu. Szereg:sqrt(1+x)= 1 + 1/2 x - 1/8 x^2 + 1/16 x^3 - 5/128 x^4 + 7/256 x^5 - 21/1024 x^6 + 33/2048 x^7 - 429/32768 x^8 + 715/65536 x^9 - 2431/262144 x^10 + 4199/524288 x^11 - 29393/4194304 x^12 + 52003/8388608 x^13

#define li 100 //liczba iteracji do szeregu
//tablicowanie fcji sin w <a,b> - szereg + funkcja biblioteczna
//definicja funkcji szereg; x - parametr formalny
double szereg(double x)
{
double s, w;
int i;
s=x;
w=1+x;
for(i=1;i<=li;i+=2)
{
    // sqrt(1+x)=1 + 1/2 x - 1/8 x^2 + 1/16 x^3 - 5/128 x^4 + 7/256 x^5 - 21/1024 x^6
 w=-w*x/2*i //?
 s=s+w;
}
return s;
}
1

https://dsp.krzaq.cc/post/445/jak-zadawac-pytania-na-forum/
Tytuł dobry
Treść, kiepska, bo nie wiadomo z czym masz problem i jakie masz wymagania co do rozwiązania.
Jest parę hasłeł, które sugerują coś bardziej ogólnego niż szereg Taylora dla f(x) = \sqrt{x + 1}

BTW: 1/2 w C daje 0!

1

taylorSeries sumuje n pierwszych wyrazów szeregu, przy okazji taylor liczy n-ty wyraz, coś to podejrzanie wolno zbieżne, ale wynik wygląda dobrze (dla x = 1 powinno dać pierwiatek z dwóch)

// Taylor sqrt(1 + x), https://planetmath.org/taylorexpansionofsqrt1x
#include <iostream>
#include <cmath>

unsigned long fact(unsigned long n) {
    if (n == 0) return 1L;
    unsigned long p = 1L;
    while (n > 0){
        p *= n;
        n--;
    }
    return p;
}

int sign(int n) {
    return powl(-1, n - 1);
}

double f(unsigned long n) { // ułamek w Szeregu Taylora
    return  fact(2 * n - 3) / ( powl(2, 2 * n - 2) * fact(n) * fact(n - 2) );
}

double taylor(unsigned long i, double x) {
    return sign(i) * f(i) * pow(x, i);
}

double taylorSeries(double x, int maxIter) { 
    if (maxIter == 0) return 1;
    if (maxIter == 1) return 0.5 * x + 1;
    int i{2};
    double s{0.5D * x + 1};
    while (i < maxIter) {
        s = s + taylor(i, x);
        i++;
    }
    return s;

}

int main () {
    std::cout << taylorSeries(1, 20) << "\n"; // -> 1.41599
    return 0;
}
1

@lion137 ten twój kod ma dużo numerycznych kwiatków.
Matematycznie może wygląda poprawnie, ale od strony informatycznej tragedia.
Samo sign to absurd. Do tego silnia jest źle liczona (szybko rośnie i nie zmieści ci się w unsigned long).
W takich zadaniach kolejne elementy szeregu liczy się na podstawie elementu poprzedniego.

1

@lion7 zauważ taką relację rekurencyjną (o ile się nie pomyliłem):

taylor(i + 1, x) = (-1) \cdot \frac {(2i - 1) \cdot (2i - 2)} {4 (i+1)*(i+2)*i*(i-1)} \cdot (1+x)^{-1} \cdot taylor(i, x)

A w kwesti zła funkcji sign, oto lepsza implementacja:

int sign(int n)
{
if (n % 2 == 0) return -1;
return 1;
}

Edycja: istotnie, jednak się pomyliłem. Oto poprawny wzór:

taylor(i+1, x) = -\frac 1 4 \cdot \frac{(2i-1)(2i-2)}{(i+1)(i-1)} \cdot taylor(i, x) / (1+x)
1

Zamieniając i + 1 na i, i automatycznie i na i - 1 i zatrzymując rekurencje na i = 2 (wtedy zeruje się mianownik, więc dalsze liczenie nie ma sensu), zaimplenetowałem tę relację, ale nie wiem jak zinterpretować jej wyniki:

double taylor2(unsigned long i, double x) { // for i >= 2
    if (i == 2) return -0.125D * x * x;
    return (-0.25) * ( (2 * i - 3) * (2 * i - 4)  / (i * (i - 2)) * (x + 1) ) * taylor2(i - 1, x);  
}

int main () {
    std::cout << taylor2(4, 1.0D) << "\n"; // -> 0.125 ??
    std::cout << taylor(4, 1.0D) << "\n"; // - > 0.0625 OK czwarty współczytnnik szeregu

    return 0;
}
1

To może najpierw popraw wzór - zamień tę linijkę

    return (-0.25) * ( (2 * i - 3) * (2 * i - 4)  / (i * (i - 2)) * (x + 1) ) * taylor2(i - 1, x);  

na taką

    return (-0.25) * ( (2 * i - 3) * (2 * i - 4)  / (i * (i - 2)) / (x + 1) ) * taylor2(i - 1, x);  
1

Upierałbym się, że to nie jest to samo co we wzorze (jak jest wszystko przez (1 + x), / (1 + x), to dla mnie jest to samo, co 1 + x wchodzące do mianownika); nieważne, zmieniłem, ale dalej nie wiem co to zwraca:

double taylor2(unsigned long i, double x) { // for i >= 2
    if (i == 2) return -0.125D * x * x;
    return (-0.25) * ( (2 * i - 3) * (2 * i - 4)  / (i * (i - 2)) / (x + 1) ) * taylor2(i - 1, x);  
}

int main () {
    std::cout << taylor2(4, 1.0D) << "\n"; // -> -0.0078125 ???
    std::cout << taylor(4, 1.0D) << "\n"; // - > -0.0390625 OK, czwarty wspólczynnik szeregu.
    return 0;
}

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