#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef struct values_s
{
    double *x;
    double *funcval ;
    double *derivate ;
    long size ;
} values_t ;

values_t * values_allocate (long size )
{
    values_t *elem;
    if(!(elem=calloc(1,sizeof(values_t))))
    {
        fprintf(stderr,"Fehler bei Speicherallozierung!\n");
        return 0;
    }
    elem->size=size;
    if(!(elem->x=calloc(size,sizeof(double))))
    {
        fprintf(stderr,"Fehler bei Speicherallozierung!\n");
        free(elem);
        return 0;
    }
    if(!(elem->funcval=calloc(size,sizeof(double))))
    {
        fprintf(stderr,"Fehler bei Speicherallozierung!\n");
        free(elem->x);
        free(elem);
        return 0;
    }
    if(!(elem->derivate=calloc(size,sizeof(double))))
    {
        fprintf(stderr,"Fehler bei Speicherallozierung!\n");
        free(elem->x);
        free(elem->funcval);
        free(elem);
        return 0;
    }
    return elem;
}

typedef enum boolean_e
{
    FALSE = 0,
    TRUE = 1
} boolean_t ;

boolean_t values_insert ( values_t *val , double x1 , double x2 , double x3 , long index )
{
    if(val==0||index<0||index>=val->size)
        return FALSE;
    val->x[index]=x1;
    val->funcval[index]=x2;
    val->derivate[index]=x3;
    return TRUE;
}

boolean_t values_free ( values_t *val)
{
    if(val==0)
        return FALSE;
    free(val->derivate);
    val->derivate=0;
    free(val->funcval);
    val->funcval=0;
    free(val->x);
    val->x=0;
    free(val);
    return TRUE;
}

boolean_t values_print ( values_t *val)
{
    if(val==0)
        return FALSE;
    long i;
    for(i=0;i<val->size;i++)
        printf("%3ld: %10g | %10g %10g\n",i,val->x[i],val->funcval[i],val->derivate[i]);
    return TRUE;
}

double function1(double x)
{
    return pow(x,4)+6*pow(x,2)-1;
}

double function2(double x)
{
    return cos(x);
}

double function3(double x)
{
    return exp(pow(x,2));
}

double function4(double x)
{
    return sqrt(pow(x,2)+3);
}

typedef double (*func_t)(double);

boolean_t differentiate ( values_t *val , func_t func )
{
    if(val==0)
        return FALSE;

    long i;
    for(i=0;i<val->size;i++)
        val->funcval[i]=func(val->x[i]);
    for(i=0;i<val->size;i++)
    {
        if(!(val->x[i+1]-val->x[i-1]))
        {
            fprintf(stderr,"Division durch 0!\n");
            return FALSE;
        }
        val->derivate[i]=(val->funcval[i+1]-val->funcval[i-1])/(val->x[i+1]-val->x[i-1]);
    }
    return TRUE;
}

boolean_t values_save ( values_t *val , char *file )
{
    if(val==0)
        return FALSE;
    FILE *f;
    if(!(f=fopen(file,"w")))
        return FALSE;
    long i;
    for(i=0;i<val->size;i++)
        fprintf(f,"%3ld: %10g | %10g %10g\n",i,val->x[i],val->funcval[i],val->derivate[i]);
    fclose(f);
    return TRUE;
}

double function5(double x)
{
    return atan(x)*x;
}

int main()
{
    printf("Nummerisches Differenzieren!\n");
    values_t *elem=values_allocate(20);
    //double x=3;
    long i;
    double ug=0,og=5;
    double dx=(og-ug)/elem->size;
    for(i=0;i<elem->size;i++,ug+=dx)
        values_insert(elem,ug,0,0,i);//hier habe ich verändert
    differentiate(elem,function1);
    values_print(elem);
    if(values_save(elem,"test.txt")!=TRUE)
        fprintf(stderr,"Fehler beim Speichern!\n");
    if(values_free(elem)!=TRUE)
    {
        fprintf(stderr,"Fehler bei Speicherfreigabe!\n");
        exit(-1);
    }
    elem=0;
    return 0;
}
