Interpolacja Newtona. zakłócenie prz dużej liczbie węzłów.

0

Witam. Napisałem "program" który ma wyznaczać wielomian interpolacyjny, wszystko jest ok, gdy liczba węzłów nie przekracza ok. 35 natomiast gdy użytkownik podaje liczbę większą np 50 na jednym z krańców przedziału dzieją się dziwne rzeczy, zamieszczam mój kod. Proszę o pomoc, jakąś wskazówkę co robię źle, interpolacja metodą Newtona na węzłach równoodległych i Czebyszewa. Do rysowania wykresów używam gnuplota.

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cmath>
#include "gnuplot_i.hpp"
#define GNUPLOT_PATH "D:\\programs\\gnuplot\\bin"
 
using namespace std;
 
int rozmiar = 0;
 
struct element
{
    double x, y;
};
 
double Newton (element* el, int rozmiar, double x)
{
    double wynik = el[0].y;
    double *a = new double [rozmiar];
 
    for (int i=0; i<rozmiar; i++)
        a[i] = el[i].y;
    for (int i=1; i<rozmiar; i++)
        for (int j=0; j<i; j++)
            a[i] = (a[i]-a[j])/(el[i].x-el[j].x);
    for (int i=1; i<rozmiar; i++)
    {
        double f = 1.0;
        for (int j=0; j<i; j++)
            f *= x - el[j].x;
        wynik += a[i]*f;
    }
    delete [] a;
    return wynik;
}
 
double fun1 (double x)
{
    return 0.05*x*x*x*x*x-1.4416*x*x*x*x+15.5666*x*x*x-77.8583*x*x+178.6833*x-149;
}
 
double fun2 (double x)
{
    return 1/(x*x+1);
}
 
element* Odczyt (string nazwa)
{
    element *tab;
    ifstream plik (nazwa.c_str());
    if (plik.good())
    {
        plik >> rozmiar;
        tab = new element [rozmiar];
        for (int i=0; i<rozmiar; i++)
            plik >> tab[i].x >> tab[i].y;
    }
    else exit;
    return tab;
}
 
void Gnu3 (double a, double b, double(* fun)(double), element* tab, int rozmiar/*, double(* fun2)(element*, int, double)*/)
{
    ofstream plik;
    plik.open("numerki.dat");
    if(plik.is_open())
    {
        for (double i=a; i<b; i=i+0.01)
        {
            plik.width(5);
            plik.fill(' ');
            plik<<left<<i<<" "<<fun(i)<<endl;
        }
        plik.close();
    }
    else exit;
    ofstream plik2;
    plik2.open("numerki2.dat");
    if(plik2.is_open())
    {
        for (double i=a; i<b; i=i+0.01)
        {
            plik2.width(5);
            plik2.fill(' ');
            plik2<<left<<i<<" "<<Newton(tab,rozmiar,i)<<endl;
        }
        plik.close();
    }
    else exit;
    system("\"\"D:\\programs\\gnuplot\\bin\\gnuplot.exe\" -p -e \"plot 'tabik.txt','numerki.dat' with lines,'numerki2.dat' with lines\"\"");
}
 
void Rowne (double a, double b, int ile_wezlow, double(* fun)(double))
{
    double odleglosc = (b-a)/(ile_wezlow-1);
    ofstream avaritia;
    avaritia.open("tab.txt");
    if (avaritia.is_open())
    {
        avaritia <<ile_wezlow<<"\n";
        for (double i=a; i<=b; i=i+odleglosc)
        {
            avaritia <<i<<" "<<fun(i)<<"\n";
        }
        avaritia.close();
    }
    else exit;
    ofstream wezly;
    wezly.open("tabik.txt");
    if (wezly.is_open())
    {
        for (double i=a; i<=b; i=i+odleglosc)
            wezly <<i<<" "<<fun(i)<<"\n";
    wezly.close();
    }
    else exit;
}
 
void Czebyszew (double a, double b, int n, double(* fun)(double))
{
    double *tab = new double [n];
    if (n%2==1)
    {
        tab[n/2]=((a+b)+(b-a)*cos((2.0*n/2+1.0)/(n+1)*M_PI/2.0))/2.0;
        for (int i=0; i<n/2; i++)
            tab[i]=((a+b)+(b-a)*cos((2.0*i+1.0)/(n+1)*M_PI/2.0))/2.0;
        for (int i=n/2+1; i<n; i++)
            tab[i]=((a+b)+(b-a)*cos((2.0*(i+1.0)+1.0)/(n+1)*M_PI/2.0))/2.0;
    }
    else
    {
        for (int i=0; i<n/2; i++)
            tab[i]=((a+b)+(b-a)*cos((2.0*i+1.0)/(n+1)*M_PI/2.0))/2.0;
        for (int i=n/2; i<n; i++)
            tab[i]=((a+b)+(b-a)*cos((2.0*(i+1.0)+1.0)/(n+1)*M_PI/2.0))/2.0;
    }
    ofstream avaritia;
    avaritia.open("tab.txt");
    if (avaritia.is_open())
    {
        avaritia<<n<<"\n";
        for (int i=0; i<n; i++)
        {
            avaritia<<tab[i]<<" "<<fun(tab[i])<<"\n";
        }
        avaritia.close();
    }
    else exit;
    ofstream wezly;
    wezly.open("tabik.txt");
    if (wezly.is_open())
    {
        for (int i=0; i<n; i++)
            wezly <<tab[i]<<" "<<fun(tab[i])<<"\n";
    wezly.close();
    }
    else exit;
    delete [] tab;
}
 
int main()
{
    double a,b;
    int ile_wezlow;
    int wybor_funkcji;
    int wybor_metody;
    cout << "Wybor funkcji" << endl;
    cout << "1: 0.05x^3-1.4416x^4+15.5666x^3-77.8583x^2+178.6833x-149"<<endl;
    cout << "2: 1/(x^2+1)"<<endl;
    cout <<endl<<"Wybierz funkcje: ";
    cin >> wybor_funkcji;
    switch (wybor_funkcji)
    {
    case 1:
        {
            cout <<endl<<"Przedzial" << endl;
            cout << "a: ";
            cin >> a;
            cout << "b: ";
            cin >> b;
            cout <<endl<< "Podaj liczbe wezlow: ";
            cin >> ile_wezlow;
            cout <<endl<< "Metoda"<<endl;
            cout << "1 - Rownoodlegle"<<endl;
            cout << "2 - Czebyszewa"<<endl;
            cout <<endl<< "Wybierz metode: ";
            cin >> wybor_metody;
            switch (wybor_metody)
            {
            case 1:
                {
                    Rowne(a,b,ile_wezlow, fun1);
                    element *A = Odczyt("tab.txt");
                    Gnu3(a,b,fun1,A,rozmiar/*,Newton*/);
                    delete [] A;
                }
                break;
            case 2:
                {
                    Czebyszew(a,b,ile_wezlow,fun1);
                    element *A = Odczyt("tab.txt");
                    Gnu3(a,b,fun1,A,rozmiar/*,Newton*/);
                    delete [] A;
                }
                break;
            }
        }
        break;
    case 2:
        {
            cout <<endl<< "Przedzial" << endl;
            cout << "a: ";
            cin >> a;
            cout << "b: ";
            cin >> b;
            cout <<endl<< "Podaj liczbe wezlow: ";
            cin >> ile_wezlow;
            cout <<endl<< "Metoda"<<endl;
            cout << "1 - Rownoodlegle"<<endl;
            cout << "2 - Czebyszewa"<<endl;
            cout <<endl<< "Wybierz metode: ";
            cin >> wybor_metody;
            switch (wybor_metody)
            {
            case 1:
                {
                    Rowne(a,b,ile_wezlow, fun2);
                    element *A = Odczyt("tab.txt");
                    Gnu3(a,b,fun2,A,rozmiar/*,Newton*/);
                    delete [] A;
                }
                break;
            case 2:
                {
                    Czebyszew(a,b,ile_wezlow,fun2);
                    element *A = Odczyt("tab.txt");
                    Gnu3(a,b,fun2,A,rozmiar/*,Newton*/);
                    delete [] A;
                }
                break;
            }
        }
        break;
    }
    return 0;
}
<image> ![7bd92cf796.png](//static.4programmers.net/uploads/attachment/7bd92cf796.png) </image>
0

Mogę się mylić, bo dawno nie miałem do czynienia z numerkami, ale czy to nie jest czasem spodziewane zachowanie interpolacji Legrange-a (duże zniekształcenia funkcji, szczególnie przy końcach przedziału) oraz interpolacji wielomianem Czebyszewa (małe zniekształcenia)? Niedoskonałość metody Legrange jest właśnie motywacją do stosowania węzłów Czebyszewa. W dalszej perspektywie (dla b. dużej liczby węzłów) stosuje się kawałkami przedziałów krzywe sklejane, które najlepiej dopasowują się do interpolowanej f-kcji. Spójrz na wykresy i komentarze pod wykresami tutaj (krzaczki można olać): http://wazniak.mimuw.edu.pl/index.php?title=MN09

0

Może masz rację, ale ja mam interpolować Newtonem a nie Lagrangem :(

0

@noname375 to nie ma znaczenia, interpolacja wielomianowa (czy to w postaci Lagranga czy Netwona) jest podatna na efekt Rungego jeśli masz równoodległe węzły.
Zapewne gdybyś doczytał / poszedł na wykład to byś wiedział że to masz właśnie w tym ćwiczeniu pokazać.

0

Wiem że tak jest, problem w tym że nawet dla węzłów Czebyszewa taka sytuacja ma miejsce.

1

A ja bym w ogóle chciał zobaczyć te twoje dane bo ten obrazek sie nie trzyma kupy. Masz tam jakieś oscylacje pomiędzy węzłami a to jest raczej jakiś WTF bo to by znaczyło że masz tam wielomian wyższego stopnia niż liczba węzłów...

0

Przesyłam dane: interp - x-sy i wartości dla interpolacji
oryginal - oryginalne wartosci wielomianu
tab - wezly
wezly - wezly (tylko do rysowania)

podaje przedział -5 do 5 i wybieram 51 węzłów.

Widać że coś się nie zgadza podczas liczenia wartości dla interpolowanego wielomianu od pewnego momentu :/

No i wybieram tą drugą funkcję 1/(x^2+1)

1

Troszkę jest to zabawne jak ktoś robi screenshota z podglądu obrazka. Nie można było po prostu dołączyć oryginalnego obrazka?

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