Interpolacja

0

Napisałem sobie 100 punktów będących węzłami interpolacyjnymi funkcji. Następnie po zinterpolowaniu tych punktów i narysowaniu węzłów oraz wykresu funkcji zinterpolowanej okazało się że została poprawnie tylko na pewnym niedużym przedziale.
Ma ktoś podejrzenia czym może być to spowodowane?

Załączam plik z punktami. Funkcję liczącą wartości funkcji interpolowanej pobrałem gotową.

Kodu nie zamieszczam poniewaz jest raczej dobry. Korzystam z gotowej funkcji. Przy 10 punktach funkcja interpolowana jest dobrze. Nie wiem tylko jaki warunek nie jest spelniony przy tych moich danych ze na wiekszosci przedzialu wychodza duze bledy. Interpoluje na przedziale xe(0;600) a wykres jest rysowany poprawnie tylko dla ok (400;500). Reszta to bardzo duze liczby rzedu e15.

0

Skąd wiesz ze wynik jest niepoprawny? Masz wzór funkcji która jest oczekiwanym rezultatem?

0

Wykres:
czerwone to wezły, niebieskie funkcja po interpolacji

0

Wiesz co, programowanie to jednak dość prosta dziedzina. Ogólnie jeśli program "jest dobry" -> zwraca dobre wyniki. Jeśli program "nie zwraca dobrych wyników" -> program nie jest dobry.

Bez kodu to przypuszczenia, światopoglądy, interpretacje... wróżbiarstwo.

0
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "winbgi2.h"
#include "inter.h"

void main ()
{
	FILE *plik=fopen("dane.txt", "r");

	int N;
	fscanf (plik, "%d", &N);
	printf ("%d\n", N);
	double *tabx;
	tabx=(double*)malloc(N*sizeof(double));
	double *taby;
	taby=(double*)malloc(N*sizeof(double));
	for (int i=0; i<N; i++)
	{
		fscanf(plik, "%lf", &tabx[i]);
		fscanf(plik, "%lf", &taby[i]);
		taby[i]=-taby[i];
		printf ("%lf\t %lf\n", tabx[i], taby[i]);
	}
	fclose (plik);

	graphics (1000,800);
	line (0,300,700,300);
	for (int i=0; i<N;i++)
	{
		setcolor(RED);
		circle (tabx[i], taby[i]+300, 4);
	}
	

	for (int i=0; i<600;i++)
	{
		double y=lagrange (tabx,taby,N,i);
		printf ("%lf\n", y);
		setcolor (0);
		circle (i, y+300, 3);
	}
	wait();
}

0

Tutaj funkcja interpolujaca

double lagrange( double *x, double *y, int n, double xx )
{
	int		i, j;
	double	yint, ylag;

	yint = 0.0;
	for ( i=0; i<n; i++ )
	{
		ylag = 1.0;
		for ( j=0; j<n; j++ )
		{
			if ( i == j)
				continue;

			ylag *= (xx - x[j]) / (x[i] - x[j]);
		}

		yint += y[i]*ylag;
	}

	return yint;
}

2

Ok teraz widzę w czym problem.
Wykraczasz poza zakres precyzji double.
Mając 128 punktów interpolując Lagrange'em dostajesz wielomian stopnia 127.
Teraz wyrazy przy dużych potęgach są dość duże i mają naprzemienne znaki. W efekcie jeśli jesteś daleko od środka, gdy wyższe potęgi mają większe znaczenie, to odejmujesz od siebie duże liczby, co jest obarczone dużym błędem, by potem dodawać do tego małe małe wartości.
Efekt jest taki, jak obserwujesz.
Matematycznie kod jest poprawny, ale ograniczenia precyzji double powoduje, że błędy obliczeń kumulują się za szybko.

Zastanawiam się czy da się to jakoś obejść? W sensie czy da się tak przekształcić ten algorytm by ograniczyć kumulowanie się błędów obliczeń.

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