funkcja tablicowanie w szereg Taylora

funkcja tablicowanie w szereg Taylora
LA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 6 lat
  • Postów:2
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

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

lion137
Rozumiem, że Chcesz policzyć n - tą sumę, czyli zsumować n pierwszych wyrazów szeregu? Czy może sqrt(1+x)z jakąś dokładnością?
LA
tak, używając poprzedniego wyrazu
lion137
Czyli rekurencyjnie, na jedno wychodzi.
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:23 minuty
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!


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
  • Postów:4944
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)

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

edytowany 1x, ostatnio: lion137
enedil
prog.cpp:30:14: error: suffix for double constant is a GCC extension [-Werror] double s{0.5D * x + 1};
lion137
Zapominam, że nie wszyscy używają gcc, to musi sobie zmienić zgodnie ze swoim kompilatorem.
enedil
No właśnie nie musi, ten dodatek jest zbędny, i tak wynik jest doublem.
lion137
To spoko, tak myślałem, ale dałem na wszelki wypadek.
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:23 minuty
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
lion137
Właśnie, cały turniej (brydż) mnie coś gryzło:-), że z tą silnią jest nie tak, trzeba to skrócić. A czemu sign to takie ``Zuo```?
MarekR22
używasz ciężkiej funkcji do czegoś prostego.
lion137
DLa przejrzystości, złożonościowo, to i tak nie zaszkodzi.
lion137
W tym modelu (jaki przyjąłem) nie da się uprościć tej silni, jest to zbieżne, ale dokładność jest słaba, bo ten ułamek szybko ucieka do zera. Nie wiem jak tego uniknąć, licząc, jak Piszesz, z poprzednich elementów.
enedil
  • Rejestracja:prawie 12 lat
  • Ostatnio:7 dni
  • Postów:1027
1

@lion7 zauważ taką relację rekurencyjną (o ile się nie pomyliłem):
<br> taylor(i + 1, x) = (-1) \cdot \frac {(2i - 1) \cdot (2i - 2)} {4 (i+1)*(i+2)<em>i</em>(i-1)} \cdot (1+x)^{-1} \cdot taylor(i, x)<br>

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

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

Edycja: istotnie, jednak się pomyliłem. Oto poprawny wzór:
<br> taylor(i+1, x) = -\frac 1 4 \cdot \frac{(2i-1)(2i-2)}{(i+1)(i-1)} \cdot taylor(i, x) / (1+x)<br>

edytowany 6x, ostatnio: enedil
lion137
Co to jest n w tej rekurencji? Jaki jest jej warunek stopu?
enedil
Czego w ogóle dotyczy pytanie? To jest tylko relacja rekurencyjna, tzn. każdy element ciągu jest definiowany za pomocą jakichś innych elementów tego samego ciągu.
enedil
W kwestii n, miało być oczywiście i, tylko się zagapiłem.
lion137
Ok, czyli, żeby to dawało ten szereg, to musi być: taylor(0, x) = 1. Ale szczerze mówiąc nie widze związku tej relacji z szeregiem Taylora dla inkryminowanej funkcji...
lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
  • Postów:4944
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:

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

enedil
  • Rejestracja:prawie 12 lat
  • Ostatnio:7 dni
  • Postów:1027
1

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

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

na taką

Kopiuj
    return (-0.25) * ( (2 * i - 3) * (2 * i - 4)  / (i * (i - 2)) / (x + 1) ) * taylor2(i - 1, x);  
lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
  • Postów:4944
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:

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

enedil
Tak, umiem operować na ułamkach. U Ciebie mnożenie było już poza mianownikiem.
enedil
I masz też rację, że coś jest nie tak, ale nie mam czasu debugować.

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.