#include <stdio.h>
#include <math.h>
// FALTA: 'SPLINE (PRECISA SPLINE?)
/*
Funções básicas de interpolação, do tipo linear,
bilinear, polinomial e spline.
Para as interpolações lineares, polinomiais e spline,
o funcionamento é:
y0 = interpol_xxx(n, x, y, x0)
onde x e y são vetores de double de tamanho n, que
descrevem em apenas alguns pontos uma função y = f(x).
O x0 é um double que é o ponto que queremos obter a
interpolação em questão.
A interpolação bilinear possui o seguinte funcionamento:
z0 = interpol_bilinear(n, m, x, y, z, x0, y0)
onde x é um vetor de tamanho n e y é um vetor de tamanho m,
z é uma matriz n por m que descreve uma função z = f(x,y)
em alguns pontos. Importante notar que o algoritmo realiza
a interpolação primeiro no eixo y e depois no x.
Exemplo:
Função y(x) = x^2 + x - 1.
Definimos x = {1,2,3,4,5} e n = 5.
Logo obtemos y = {1,5,11,19,29}, aplicando y(x) em um
loop.
-- A partir de agora, só temos conhecimento de x e y,
-- a expressão de y(x) não é mais conhecida.
Queremos y0 = y(x0) em x0 = 3.5. Claramente não temos
o valor exato nos vetores, logo necessitamos realizar
uma interpolação:
x0 = 3.5
y0 = interpol_xxx(n, x, y, x0)
No final temos que y0 = 15, muito próximo do resultado
real, y(3.5) = 14.75
Observações:
Um polinômio de grau N-1 pode ser descrito perfeitamente por N pontos, e vice-versa.
Para muitos pontos (n > 5), a interpolação polinomial se
torna instável, então não é recomendada.
*/
double interpol_linear(int n, double x[n], double y[n], double x0)
{
int k, i;
for(i = 1; i < n; i++) // Encontrar índices vizinhos
{
if(x0 <= x[i])
{
k = i - 1;
break;
}
}
if(i == n) k = i - 2;
return (y[k+1] - y[k])/(x[k+1] - x[k])*(x0 - x[k]) + y[k];
}
double interpol_polinomial(int n, double x[n], double y[n], double x0)
{
double soma = 0;
int i, j;
for(i = 0; i < n; i++)
{
double produto = 1;
for(j = 0; j < n; j++)
{
if(j != i)
{
produto *= (x0 - x[j])/(x[i] - x[j]);
}
}
soma += produto * y[i];
}
return soma;
}
double interpol_bilinear(int n, int m, double x[n], double y[m], double z[n][m], double x0, double y0)
{
double zn1, zn2;
int i,kx;
for(i = 1; i < n; i++) // Encontrar índices vizinhos
{
if(x0 <= x[i])
{
kx = i - 1;
break;
}
}
zn1 = interpol_linear(m, y, z[kx], y0);
zn2 = interpol_linear(m, y, z[kx+1], y0);
double xpos[2] = {x[kx],x[kx+1]};
double zpos[2] = {zn1,zn2};
return interpol_linear(2, xpos, zpos,x0);
}
/* ----------- COMEÇO DO EXEMPLO ----------- */
double f(double x)
{
return 0.1*x*x*x + x*x + x - 1;
}
int main(void)
{
double x[4] = {1,2,3,4}, y[4], x0 = 0.9;
int i;
for(i = 0; i < 4; i++) y[i] = f(x[i]);
printf("x\t=\t%f\nf(x)\t=\t%f\nl(x)\t=\t%f\np(x)\t=\t%f\n", x0, f(x0), interpol_linear(4,x,y,x0), interpol_polinomial(4,x,y,x0));
double zn[2][2] ={{0,1},{2,3}};
double xn[2] = {0,1};
double yn[2] = {0,1};
printf("%f",interpol_bilinear(2,2,xn,yn,zn,0.5,0.5));
// Interpolação polinomial retorna ponto exato pois a
// função é de 3° grau, e são 4 pontos.
}
/* ------------ FIM DO EXEMPLO ------------ */
Comments