#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef double (*func_t)(double);

double function1(double x)
{
    return 2*sin(x)-0.5;
}

double function2(double x)
{
    return 2*cos(x);
}

typedef struct values_s
{
    double *arg;
    double * funcval ;
    long size ;
} values_t ;

typedef enum boolean_e
{
    FALSE = 0,
    TRUE = 1
} boolean_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;
    }
    if(!(elem->arg=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->arg);
        free(elem);
        return 0;
    }
    elem->size=size;
    return elem;
}

boolean_t values_insert ( values_t *val , double arg , double value , long index )
{
    if(!val||index<0||index>=val->size)
        return FALSE;
    val->arg[index]=arg;
    val->funcval[index]=value;
    return TRUE;
}

boolean_t values_free ( values_t *val)
{
    if(!val)
        return FALSE;
    free(val->arg);
    val->arg=0;
    free(val->funcval);
    val->funcval=0;
    free(val);
    //val=0;
    return TRUE;
}

boolean_t values_print ( values_t *val)
{
    if(!val)
        return FALSE;
    long i;
    for(i=0;i<val->size;i++)
        printf("%ld: %10g %10g\n",i,val->arg[i],val->funcval[i]);
    return TRUE;
}

double newton_step (double x0 , func_t func , func_t derivate )
{
    if(!derivate(x0))
    {
        fprintf(stderr,"Division durch 0!\n");
        return x0;
    }
    return x0-func(x0)/derivate(x0);
}

boolean_t newton_iter(values_t *val, double x0, double genauigkeit, double schritte, func_t func, func_t derivate)
{
    if(!val)
        return FALSE;
    long i;
    for(i=0;i<val->size&&i<schritte;i++)
    {
        values_insert(val,x0,func(x0),i);
        if(fabs(func(x0))<genauigkeit)//absoluter Wert von func(x0)
            break;
        x0=newton_step(x0,func,derivate);
    }
    return TRUE;
}

boolean_t values_store(values_t *val,char *file)
{
    if(!val)
        return FALSE;
    FILE *f;
    if(!(f=fopen(file,"w")))
        return FALSE;
    long i;
    for(i=0;i<val->size;i++)
        fprintf(f,"%ld: %10g %10g\n",i,val->arg[i],val->funcval[i]);
    fclose(f);
    return TRUE;
}

int main()
{
    printf("Newton-Verfahren!\n");
    values_t *elem;
    double x0=3;
    double genauigkeit = 0.0001;
    elem=values_allocate(5);
    newton_iter(elem,x0,genauigkeit,elem->size,function1,function2);
    values_print(elem);
    if(values_store(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;
}
