Rozwinięcie w szereg dwumianu Newtona

0

Cześć wszystkim, mam napisać program w C wyświetlający wartości funkcji (x+1)n w zadanym przedziale używając funkcji pow oraz rozwinięcia w szereg. Niestety mam z tym spory problem, a konkretnie 2:
1)wg. tego http://en.wikipedia.org/wiki/Binomial_theorem powinienem zaczynać mnożyć od x0. Problem w tym, że nie za bardzo wiem jak to zapisać w kodzie, obecnie przypisuje tmp=x i później potęguję tmp mnożąc przez x.
2) w treści zadania jest zaznaczone, że każdy wyraz powinienem obliczać używając poprzedniego, bez korzystania z dodatkowej funkcji silnia, również nie mam pomysłu na implementację tego w funkcji szereg.

Będę wdzięczny za każdą wskazówkę, jestem początkujący, dodatkowo na analizie matematycznej nie było jeszcze żadnej wzmianki o rozwinięciu w szereg, wiem, że to żadne usprawiedliwienie, a problem prawdopodobnie jest trywialny, totalnie się jednak zaciąłem.

 #include <stdio.h>
#include <math.h>

int silnia(int x)
{
int i;
int wynik=1;

for(i=2;i<=x;i++)
wynik*=i;

return wynik;
}

double szereg(double x, double m)
{
double w,s,tmp;
int i=1;
w=1;
s=0;
tmp=x;

for(i=1;i<=m;i++)
        {
                w=(silnia(m)/silnia(i)*silnia(m-i))*tmp;
                s+=w;
                tmp*=x;
        }
return s;
}



int main() {
double x,a,b,dx,m;
int lp=10;

        printf("Podaj a: ");
        scanf("%lf",&a);
        printf("Podaj b: ");
        scanf("%lf",&b);
        printf("Podaj wykladnik potegi: ");
        scanf("%lf",&m);
        dx=(b-a)/lp;
        printf("    |    x       |  pow((1+x),m)    |   szereg(x) |\n");
        printf("    ----------------------------------------\n");
                for(x=a;x<=b;x+=dx)
                        {

                                printf("    | %10.4lf | %10.4lf | %10.4lf  |\n",x,pow((1+x),m),szereg(x,m));

                        }





return 0;
}
0
  1. Ty sobie jaja robisz? x0 = 1 więc zwyczajniej zacznij od tmp = 1 a potem mnóż przez x.
  2. Nie rozumiem pytania. Zwyczajnie masz tu sytuację gdzie kolejny wyraz ciągu = poprzedni wyraz * cośtam. Więc w każdym kroku zapamiętujesz poprzedni wyraz i wykorzystujesz go do obliczenia poprzedniego.
    Wyobraźmy sobie że masz szereg S(x) = 1 + x/2 + x2/4 + x3/8 + ....
    widzisz chyba że w takim razie kolejne wyrazy szeregu to:
    a(0) = 1
    a(1) = x/2
    a(2) = x2/4
    a(3) = x3/8
    ...
    a(n-1) = xn-1/2n-1
    a(n) = xn/2n
    Z czego wynika jasno że a(n) = a(n-1) * x/2
    Licząc więc kolejne przybliżenia w pętli masz
aktualny_wyraz = poprzedni_wyraz = 1;
suma = 0;
while(warunek_konca){
  suma += aktualny_wyraz;
  poprzedni_wyraz = aktualny_wyraz;
  aktualny_wyraz = poprzedni_wyraz * x/2;
}

i voila.

0
  1. Nie robię sobie jaj, jasne, że x0=1. Naprawione, brakowało nawiasu przy liczeniu zmiennej w, w funkcji szereg.
  2. Wiem, że się napracowałeś i generalnie Twój przykład rozumiem. Ale jak zapisać ogólnie rozwinięcie tej funkcji w szereg w c?
    Mam:
    zmienna=0;
    wykladnik=0;
    wyraz= (n po zmienna)*xwykladnik;
    zmienna++;
    wykladnik++;

Ale jak tam jeszcze w środku liczyć to (n po zmienna)?
Nie wiem jak to zapisać w C, żeby całość była w funkcji szereg, teraz mam obejście że za każdym razem liczę używając silnia(x), a powinienem używać poprzedniego wyrazu do obliczenia.

0

Ok, rozumiem. Musisz mieć zadaną dokładność tego rozwinięcia, albo liczbę wyrazów szeregu które masz zsumować, innej rady nie ma.
Ale ty chyba nie do końca rozumiesz co robisz. Napisz jak wygląda rozwinięcie tej twojej funkcji w szereg, tzn jaki jest wzór tego szeregu.
Czy dobrze rozumiem że:
a(0) = 1
a(i) = (n! * xi) / (n-i)!i!
?
No to przecież widzisz że
a(i-1) = (n! * xi-1)/(n-i-1)!
(i-1)!
A jeśli rozumiesz że n! = (n-1)!*n to wynika z tego że:
a(i) = (n!xi-1x)/(n-i-1)!(n-1)(i-1)!*i = [(n!xi-1)/(n-i-1)!(i-1)!] *x/(n-1)*i = a(i-1)*x/(n-1)*i

0

user image

Czy zadaną dokładnością nie jest w tym wypadku n?

0

Jest :) patrz na mój post edytowany wyżej.

0

Czyli wtedy to powinno wyglądać jakoś tak i również odpada używanie tmp?

 double potega(double x, double m)
{
double w,s,tmp;
int i;
w=1;
s=0;
tmp=1;

for(i=1;i<=m;i++)
        {
                w=w*((i-1)*x)/((m-1)*i);
                s+=w;
                tmp*=x;
        }
return s;
}
0

Nie, nie, nie! OMG, co ty miałeś z matematyki w podstawówce? o_O Przecież jedno z drugim nie ma nic wspólnego! Napisalem ci wyżej pseudo-kod, nic w nim nie musiałeś zmieniać! Brak mi słów.

double current=previous=1;
double sum=0;
 
for(i=1;i<=m;i++)
{
    sum += current;
    previous = current;
    current = previous * x / ((n-1)*i);
}
return sum;
0

Jaki związek z problemem ma moja ocena z matematyki w podstawówce? Doceniam pomoc i to bardzo, ale zaoszczędziłbyś sobie niepotrzebnych nerwów i marnowanego na mnie czasu pokazując mi kawałek gotowej implementacji i linijką wyjaśnienia i w tym wypadku nie jest to brak samodzielnej pracy, bo po prostu tego nie rozumiem.
Tutaj wyznaczyłeś a(i)=a(i-1)*x/(n-1)*i czyli wzór na kolejny wyraz szeregu, następnie mówisz, że to w ogóle nie ma związku i mam użyć tego:

double current=previous=1;
double sum=0;
 
for(i=1;i<=m;i++)
{
    sum += current;
    previous = current;
    current = previous * x / ((n-1)*i);
}
return sum; 
0

Ty teraz pytasz poważnie? Bo zaczynam mieć wątpliwości...
Pokażę ci magiczną sztuczkę:
a(i)=a(i-1)*x/(n-1)*i
oznaczmy teraz a(i) jako current, a(i-1) jako previous i co się dzieje? Magia! Nagle
a(i)=a(i-1)*x/(n-1)*i zamienia się w current=previous*x/(n-1)*i!
Kto by pomyślał! Niesłychane! To jest ten sam wzór!

0

Uwielbiam sarkazm, nawiasem mówiąc tak, podstawiłem dokładnie wg. Twojego zalecenia już po pierwszym komentarzu o mojej matematyce. Zupełnie nie działa, dlatego dopytuję w każdy możliwy sposób.

0

Nasz rację, jest tam mały błąd w wyprowadzeniu. Reszta jest ok. Popraw to wyprowadzenie i będzie śmigać. Pomyliłem się i zamiast dzielenia zrobiłem w jednym miejscu mnożenie :) W implementacji musisz jednak uwzględnić dwa przypadki granicznej, tzn dodać ręcznie 1 oraz ostatni wyraz szeregu. Bo w pętli nie obsłużysz poprawnie przypadku dla i=0 oraz i=n bo 0! = 1 ;]

0

Przyjrzałem się temu szukając błędu: a(i) = (n!xi-1x)/(n-i-1)!(n-1)(i-1)!*i = [(n!xi-1)/(n-i-1)!(i-1)!] *x/(n-1)*i = a(i-1)*x/(n-1)*i
ale go nie znalazłem, dzielenie/mnożenie wydaje się być ok.

0

Ani trochę :D Babol jest bardzo prosty, ale nie taki łatwy do zauważenia :)
n! = (n-1)!*n
Ale ile wynosi (n-i)!? Robi sie tu misz-masz przez to odejmowanie ;]
(n-i)! = (n-i-1)!*(n-i) ! To znaczy że mając w k-tym wyrazie szeregu (n-k)! i "cofając się" do wyrazu poprzedniego gdzie mamy (n-k-1)! musimy PODZIELIĆ przez (n-k) a nie pomnożyć...
W efekcie :

#include <iostream>
#include <cmath>
using namespace std;

double fun(double x, int n){
	double current, previous;
	current = 1;
	previous = 1;
	double sum = 1;

	for(int i=1;i<=n;i++)
	{
	    sum += current;
	    previous = current;
	    current = previous * x * (n-i+1) / i; //zauważ że człon (n-i+1) jest tutaj w liczniku!
	    cout<<"current "<<current<<endl;
	}
	return sum;
}

int main() {
	double x = 1.0;
	double n = 10;
	cout<<fun(x,n)<<" "<<pow(1+x,n);
	return 0;
}
0

Bardzo dziękuję za pomoc :)!

Teraz rozumiem o co chodzi.

0

Pospieszyłem się, z jakiegoś powodu nie działa tak jak powinno.

 
#include <stdio.h>
#include <math.h>

int silnia(int x)
{
int i;
int wynik=1;

for(i=2;i<=x;i++)
wynik*=i;

return wynik;
}

double potega(double x, double m)
{
double w,s,tmp;
int i=1;
w=0;
s=0;
tmp=1;

for(i=0;i<=m;i++)
        {
                w=(silnia(m)/(silnia(i)*silnia(m-i)))*tmp;
                s+=w;
                tmp*=x;
        }
return s;
}

double szereg(double x, double m)
{
double current, previous;
    current = 1;
    previous = 1;
    double sum = 1;
    int i=1;

    for(i=1;i<=m;i++)
    {
        sum += current;
        previous = current;
        current = previous * x * (m-i+1) / i;
    }
    return sum;
}

int main() {
double x,a,b,dx,m;
int lp=10;

        printf("Podaj a: ");
        scanf("%lf",&a);
        printf("Podaj b: ");
        scanf("%lf",&b);
        printf("Podaj wykladnik potegi: ");
        scanf("%lf",&m);
        dx=(b-a)/lp;
        printf("    |    x       |  pow((1+x),m)    |   szereg(x) |\n");
        printf("    ----------------------------------------\n");
                for(x=a;x<=b;x+=dx)
                        {

                                printf("    | %10.4lf | %10.4lf | %10.4lf  |\n",x,pow((1+x),m),szereg(x,m));

                        }





return 0;
}

user image

1
	    previous = current;
	    current = previous * x * (n-i+1) / i;
	    sum += current;

W takiej kolejności oczywiście ;] Inaczej gubimy ostatni wyraz szeregu a sumujemy dwukrotnie wyraz zerowy. Bo to że na początku mamy current, previous i sum na 1 wynika z tego że obsługujemy specjalnie wyraz 0.

0

Jeszcze raz bardzo dziękuję za pomoc!

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