#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef double(*func_t)(double);
 
double polynom (double);
double cosine (double);
double exp (double);
double squareroot (double);
 
 
typedef struct values_s{
    double *x;
    double *funcval;
    double *derivate;
    long size;
} values_t;
 
typedef enum boolean_e{
    FALSE = 0,
    TRUE = 1
} boolean_t;
 
values_t *values_allocate(long size)
{
    values_t *val=calloc(1,sizeof(values_t));
 
    if(!val) return 0;
 
    val->x = calloc(size,sizeof(double));
    val->funcval = calloc(size,sizeof(double));
    val->derivate = calloc(size,sizeof(double));
 
    if(!val->x || !val->funcval || !val->derivate)
    {
        free(val);
        return 0;
    }
 
    val->size = size;
    return val;
}
 
boolean_t values_insert(values_t *val,double x1, double x2, double x3,long index)
{
    boolean_t status=FALSE;
 
    if(!val) return status;
    if(index<0 || index>=val->size) return status;
 
    val->x[index] = x1;
    val->funcval[index] = x2;
    val->derivate[index] = x3;
 
    return status=TRUE;
}
 
boolean_t values_free(values_t *val)
{
    boolean_t status=FALSE;
 
    if(!val) return status;
 
    free(val->x);
    free(val->funcval);
    free(val->derivate);
    free(val);
 
    return status=TRUE;
}
 
boolean_t values_print(values_t *val)
{
    boolean_t status=FALSE;
    long i;
 
    if(!val) return status;
 
    for(i=0;i<val->size;i++)
    {
        printf("%ld.:\t%lf\t%lf\t%lf\n",i+1,val->x[i],val->funcval[i],val->derivate[i]);
    }
 
    return status=TRUE;
}
 
boolean_t differentiate(values_t *val, func_t func)
{
    boolean_t status=FALSE;
    long i;
 
    if(!val) return status;
 
    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])) == 0) //Nenner = 0 !
        {
            fprintf(stderr,"Error: Division by Zero!\n");
            val->derivate[i]=0;
            continue;
        }
 
        val->derivate[i]=(val->funcval[i+1]-val->funcval[i-1])/((val->x[i+1]-val->x[i-1]));
    }
 
    return status=TRUE;
}
 
boolean_t values_save(values_t *val)
{
    boolean_t status=FALSE;
    FILE *fp;
    long i;
 
    if((fp = fopen("C:\\Programme\\gnuplot\\bin\\p2ue4_diff.txt","w")))
    {
        if(val)
        {
            for(i=0;i<val->size;i++)
                fprintf(fp,"%lf\t%lf\t%lf\n",val->x[i],val->funcval[i],val->derivate[i]);
        }
        else return status;
    }
    else return status;
    fclose(fp);
    return status=TRUE;
}
 
void values_plot()
{
    FILE *gnuplot = popen("C:\\Programme\\gnuplot\\bin\\gnuplot -persist","w");
 
    if (gnuplot)
    {
        fprintf(gnuplot, "set title 'P2-UE4: Diff'\n");
        fprintf(gnuplot, "set style data lines\n");
        fprintf(gnuplot, "set xlabel 'x'\n");
        fprintf(gnuplot, "set ylabel 'f(x)'\n");
        fprintf(gnuplot, "set yrange [-1.1:1.1]\n");
        fprintf(gnuplot, "cd 'C:\\Programme\\gnuplot\\bin'\n");
        fprintf(gnuplot, "plot \"p2ue4_diff.txt\" using 1:2, \"p2ue4_diff.txt\" using 1:3\n");
    }
    pclose(gnuplot);
}
 
int main()
{
    long i;
    values_t *tmp;
    tmp=values_allocate(500);
 
    double x=2*M_PI/500;
 
    for(i=0;i<500;i++)
        values_insert(tmp,(x*i),0,0,i);
 
    differentiate(tmp,cosine);
 
    values_print(tmp);
 
    values_save(tmp);
 
    values_plot();
 
    values_free(tmp);
 
    return 0;
}