the code below is a working code that runs perfectly:

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

double function(double x)
{
    return x*sin(x);
}

double exact_integral(double x)
{
    return sin(x) - x*cos(x);
}

int main(int argc, char* argv[])
{

    /// Check parameters
    if(argc != 3) {
        fprintf(stderr, "Wrong number of parameters\nUsage:\n\t%s N XMAX\n", argv[0]);
        return -1;
    }

    int N = (int)strtol(argv[1], NULL, 10);
    double X_MAX = (double) strtold(argv[2], NULL);
    double deltaX = X_MAX/(double) N;
    double* integral = (double *) calloc(N+1, sizeof(double));


    clock_t start_time = clock();
    int i;
    for (i = 1; i <= N; i++){
        double x = (i-0.5)*deltaX;
        integral[i] = integral[i-1] + deltaX*function(x);
    }

    double def_result = integral[N];
    double exact = exact_integral(X_MAX);
    double error = fabs(def_result - exact);
    double run_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
    printf("Result with N=%d is %.12lf (%.12lf, %.2e) in %lf seconds\n", N, def_result, exact, error, run_time);

    /// Print integral data
    char filename_dat[100];
    sprintf(filename_dat, "indef_integral_seq.dat");
    FILE* file_dat = fopen(filename_dat, "wb");
    if (file_dat != NULL) {
        fwrite(integral, sizeof(integral), N+1, file_dat);
        fclose(file_dat);
    }
    
    /// Print integral info
    char filename_info[100];
    sprintf(filename_info, "indef_integral_seq.info");
    FILE* file_info = fopen(filename_info, "w");
    if (file_dat != NULL) {
        fprintf(file_info, "# %s\n", "Indefinite integral version sequential");
        fprintf(file_info, "data %s\n", filename_dat);
        fprintf(file_info, "N %d\n", N + 1);
        fprintf(file_info, "XMAX %lf\n", X_MAX);
        fprintf(file_info, "size %d\n", 1);
        fclose(file_info);
    }

    free(integral);
    return 0;
}

the following code is a modification of the code above but using parallelization with MPI. It must give the same ouput as the code above but faster. However for some reason it doesn't give the same output because with the same input parameters for N = 10 and XMAX = 1000 the graphic scale is different for both codes. In the sequential the graphic is correct having 'x' go from 0 to 1000 and integral(x) going from -100000 to 100000. But in the case of the parallelized code the integral(x) goes from -60000 to 80000. So what is happening and how can i fix it? One hint that the exercise gives me is that i need to implement MPI_Recv and MPI_Send somehow.

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

double function(double x)
{
    return x * sin(x);
}

double exact_integral(double x)
{
    return sin(x) - x * cos(x);
}

int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);

    int rank, size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    /// Check parameters
    if (argc != 3) {
        if (rank == 0) {
            fprintf(stderr, "Wrong number of parameters\nUsage:\n\t%s N XMAX\n", argv[0]);
        }
        MPI_Finalize();
        return -1;
    }

    int N = (int)strtol(argv[1], NULL, 10);
    double X_MAX = (double)strtold(argv[2], NULL);
    double deltaX = X_MAX / (double)N;

    // Distribute work among ranks
    int local_N = N / size;
    double local_X_MAX = X_MAX / size;
    double local_deltaX = local_X_MAX / (double)local_N;

    double* local_integrals = (double*)calloc(local_N, sizeof(double));
    for (int i = 0; i < local_N; i++) {
        double x = (rank * local_X_MAX + (i - 0.5) * local_deltaX);
        local_integrals[i] = local_deltaX * function(x);
    }

    

    // Gather results from all ranks
    double* all_integrals = NULL;
    if (rank == 0) {
        all_integrals = (double*)calloc(N, sizeof(double));
    }
    MPI_Gather(local_integrals, local_N, MPI_DOUBLE, all_integrals, local_N, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    if (rank == 0) {
        double def_result = 0.0;
        for (int i = 0; i < N; i++) {
            def_result += all_integrals[i];
        }

        double exact = exact_integral(X_MAX);
        double error = fabs(def_result - exact);
        double run_time = (double)(clock()) / CLOCKS_PER_SEC;
        printf("Result with N=%d is %.12lf (%.12lf, %.2e) in %lf seconds\n", N, def_result, exact, error, run_time);

        /// Print integral data
        char filename_dat[100];
        sprintf(filename_dat, "indef_integral_mpi.dat");
        FILE* file_dat = fopen(filename_dat, "wb");
        if (file_dat != NULL) {
            fwrite(all_integrals, sizeof(double), N, file_dat);
            fclose(file_dat);
        }

        /// Print integral info
        char filename_info[100];
        sprintf(filename_info, "indef_integral_mpi.info");
        FILE* file_info = fopen(filename_info, "w");
        if (file_info != NULL) {
            fprintf(file_info, "# %s\n", "Indefinite integral version parallel (MPI)");
            fprintf(file_info, "data %s\n", filename_dat);
            fprintf(file_info, "N %d\n", N);
            fprintf(file_info, "XMAX %lf\n", X_MAX);
            fprintf(file_info, "size %d\n", size);
            fclose(file_info);
        }

        // Free the all_integrals array
        free(all_integrals);
    }

    // Free the local_integrals array
    free(local_integrals);
    MPI_Finalize();
    return 0;
}