Engine
Engine

Reputation: 5432

implementation of trapezoidal numerical integration in C

I'm trying to implement numerical integration using the trapezoidal approximation using this formula : formel

My problem is I don't get how to implement this correctly. To test I wrote a file with 22050 double values all equal to 2 like :

....................
    value =2.0;
    for ( index = 0 ; index < 22050;index++){           
            fwrite(&value,sizeof(double),1,inp2);
        }

to keep the question simple, say I want to the integral value of each 100 samples:

 X Area                integral value 
0-100               should be  200  
100-200             should be  200
.....                ...........
22000-22050         should be  100

to do that I 've wrote a program that should do that but the result that get is 4387950 for 100 samples here is my code :

..............................
    // opening the files 

double* inputData= NULL;
unsigned int N = 100;
double h= 0.0;
unsigned int index= 0;
FILE* inputFile=NULL;
double value =0.0;
int i =0,j=0;


    inputFile = fopen("sinusD","rb");
    outputFile=fopen("Trapez","wb+");
    if( inputFile==NULL || outputFile==NULL){
        printf("Couldn't open the files \n");
        return -1;
    }
    inputData = (double*) malloc(sizeof(double)*N);

    h=22050/2;
    while((i = fread(inputData,sizeof(double),N,inputFile))==N){
        value += inputData[0] +inputData[N];
        for(index=1;index<N;index++){
            value+=(2*inputData[index]);
        }
        value *=h;
        fprintf(outputFile,"%lf ",value);
        value =0;

    }
    if(i!=0){
        value = 0;
        i=-i;
        printf("i value %i\n", i);
        fseek(inputFile,i*sizeof(double),SEEK_END);
        fread(inputData,sizeof(double),i,inputFile);
            for(index=0;index<-i;index++){
            printf("index %d\n",index);
            value += inputData[0] +inputData[i];
            value+=(2*inputData[index]);
        }
        value *=h;
        fprintf(outputFile,"%lf ",value);
        value =0;
    }
    fclose(inputFile);
    fclose(outputFile);
    free(inputData);
    return 0;}

any idea how to do that ?

UPDATE

while((i = fread(inputData,sizeof(double),N,inputFile))==N){
    value = (inputData[0] + inputData[N])/2.0;
    for(index=1;index<N;index++){
        value+=inputData[index];
    }
    value *=h;
    fprintf(outputFile,"%lf ",value);
    printf(" value %lf\n",value);
    value =0;

}

I get 199.000 as a result for each segment .

Upvotes: 1

Views: 4780

Answers (2)

CroCo
CroCo

Reputation: 5741

Why you didn't start with something simple. Let's say you have the following data {1,2,3,4,5,6,7,8,9,10} and assume h = 1. This is simple,

#include <stdio.h>

#define SIZE 10

int main()
{
    double a[SIZE] = {1,2,3,4,5,6,7,8,9,10}, sum = 0.0, trapz;
    int h = 1;
    int i = 0;

    for ( i; i < SIZE; ++i){
        if ( i == 0 || i == SIZE-1 ) // for the first and last elements
            sum += a[i]/2;
        else
            sum += a[i]; // the rest of data
    }   
    trapz = sum*h; // the result

    printf("Result: %f \n", trapz);
    return 0;
}

This is the result

Result: 49.500000

Double check your work with Matlab:

Y = [1 2 3 4 5 6 7 8 9 10];
Q = trapz(Y)

Q =

   49.5000

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Edit: For your question in the comment: This is the matlab code:

X = 0:pi/100:pi; % --> h = pi/100
Y = sin(X); % get values as many as the size of X
Q = trapz(X,Y);
Q =
    1.9998

Now to fulfil same scenario in C, do the following

#include <stdio.h>
#include <math.h>

#define SIZE 101

#define PI 3.14159265358

int main()
{
    double X[SIZE], Y[SIZE], incr = 0.0, h = PI/100.0, sum = 0.0, trapz;
    int i = 0, k = 0, j = 0;

    // Generate samples
    for ( i; i < SIZE; ++i)
    {
        X[i] = incr;
        incr += h;
    }

    // Generate the function Y = sin(X)
    for ( k; k < SIZE; ++k)
    {
        Y[k] = sin(X[k]);
    }

    // Compute the integral of sin(X) using Trapezoidal numerical integration method
    for ( j; j < SIZE; ++j){
        if ( j == 0 || j == SIZE-1 ) // for the first and last elements
            sum += Y[j]/2;
        else
            sum += Y[j]; // the rest of data
    }   
    trapz = sum * h; // compute the integral

    printf("Result: %f \n", trapz);

    return 0;
}

The result is

Result: 1.999836

Upvotes: 2

Edward
Edward

Reputation: 7100

First, your equation is correct, so that's a good start. However, there are a number of variable declarations that you don't supply in your question, so we're left to guess.

First, let's start with the math. For the integral from 0 to 100 to equal 200 with each value being equal to 2.0 implies that h = 1 but your code seems to use a value of 22050/2 which is probably not really what you want.

The code within the loop should look like this:

double value = (inputData[0] + inputData[N])/2.0;
for(index = 1; index < N; ++index){
    value += inputData[index];
}
value *= h;

This will give the integral from 0 to N. If you wish to calculate between two arbitrary values, you will have to modify the code appropriately:

int a = 100;  // lower limit
int b = 200;  // upper limit 

double value = (inputData[a] + inputData[b])/2.0;
for(index = a+1; index < b; ++index){
    value += inputData[index];
}
value *= h;

As a full example of use, here's a program to calculate the integral of sin(x) from x=pi/4 to x=pi/2:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define M_PI        3.14159265358979323846

int main()
{
    int a = 45;   // 45 degrees = pi/4 radians
    int b = 90;   // 90 degrees = pi/2 radians
    double h = M_PI/180;   // how far apart are samples?
    double *inputData = malloc(360*sizeof(double));
    if (inputData == NULL) {
        printf("Error: ran out of memory!\n");
        exit(1);
    }
    for (int i=0; i<360; ++i)
        inputData[i] = sin(i*h);

    double value = (inputData[a] + inputData[b])/2.0;
    for (int index = a+1; index < b; ++index)
        value += inputData[index];
    value *= h;
    printf("integral from %d to %d = %f\n", a, b, value);
    double expected = 1.0/sqrt(2);
    printf("(expected value = %f, error = %f)\n", expected, expected-value);
    free(inputData);
}

Output from this program on my machine:

integral from 45 to 90 = 0.707089
(expected value = 0.707107, error = 0.000018)

Upvotes: 1

Related Questions