How to generate array of random numbers using func

2019-07-10 11:00发布

问题:

I am trying to port a program from Matlab to C in order to improve the execution time and the memory usage. Since there are not functions in C which generate uniformly populated arrays of 0 and 1 (or I could not find them) I created a function to populate an array accordingly to the associated probability.

Example: if the probability is 0.3 (30%) I would like to have an array of 100 elements, populated randomly with zeros and ones, and the sum of ones of the array must be close to 30.

Instead of 100 I use N = number of trials, so if N=10000 then the sum of ones of the array should be something close to 3000, etc.

The function in Matlab is just:

function [y] = rand_gen(N,Prob)

    for i=1:N
        y(i,1) = binornd(1,Prob);
    end
end

The function would be called as:

array = rand_gen(N, Probability);

Now, here is the issue in C: when I run the program I can generate some arrays but the maximum number of trials (N) its very low, and I don't think its a matter of memory. If I run the program with N = 100000 everything goes ok, but after 100000 (and something) crashes. The program in C is:

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

int * rand_gen(int N, double Prob); // Function declaration
int sum_array(int a[], int num_elements);    // Function declaration

int main()  // Main function
{
int N;  // Declaration: Number of trials
printf("Number of trials: ");
scanf("%d", &N);    // Asks for Number of trials

double Prob_a = 0.5;   // Probability (50%)
int i;  // Declaration: Index
int sum; // Declaration: sum of elements of arrays
int bin_array_0[N]; // Declaration: array populated randomly by 0 and 1
int bin_array_1[N]; // Declaration: array populated randomly by 0 and 1
int bin_array_2[N]; // Declaration: array populated randomly by 0 and 1
int bin_array_3[N]; // Declaration: array populated randomly by 0 and 1
int *ptrnd = NULL; // Declaration: pointer to array
int seed = time(NULL); // Declaration: random number generator seed (based on current time)
srand(seed);


ptrnd = rand_gen(N, Prob_a);    // Populate a temporary array with 0 and 1 using the rand_gen function

for(i=0 ; i<N ; i++)
{
    bin_array_0[i] = *(ptrnd + i);
}
/* Print the sum of ones in the array
 * in order to check the rand_gen probability
 * reliability and compare to the temp array   */
sum = sum_array(bin_array_0, N);
printf("\n The sum of the bin_array_0 is %d\n", sum);



ptrnd = rand_gen(N, Prob_a);    // Populate a temporary array with 0 and 1 using the rand_gen function

for(i=0 ; i<N ; i++)
{
    bin_array_1[i] = *(ptrnd + i);
}
/* Print the sum of ones in the array
 * in order to check the rand_gen probability
 * reliability and compare to the temp array   */
sum = sum_array(bin_array_1, N);
printf("\n The sum of the bin_array_1 is %d\n", sum);


ptrnd = rand_gen(N, Prob_a);    // Populate a temporary array with 0 and 1 using the rand_gen function

for(i=0 ; i<N ; i++)
{
    bin_array_2[i] = *(ptrnd + i);
}
/* Print the sum of ones in the array
 * in order to check the rand_gen probability
 * reliability and compare to the temp array   */
sum = sum_array(bin_array_2, N);
printf("\n The sum of the bin_array_2 is %d\n", sum);


ptrnd = rand_gen(N, Prob_a);    // Populate a temporary array with 0 and 1 using the rand_gen function

for(i=0 ; i<N ; i++)
{
    bin_array_3[i] = *(ptrnd + i);
}
/* Print the sum of ones in the array
 * in order to check the rand_gen probability
 * reliability and compare to the temp array   */
sum = sum_array(bin_array_3, N);
printf("\n The sum of the bin_array_3 is %d\n", sum);

return(0);

}


// Function: generate an array populated by 0 and 1 according to a uniformed distribution
int * rand_gen(int N, double Prob)
{
    int sum; // Declaration: sum of elements of arrays
    int *array;
    array = (int *)malloc(sizeof(int)*N);
    if(array == NULL)
    {
        printf("\nRun out of memory!\n");
        exit(1);
    }

    int j;
    double x;

    for(j=0; j<N; j++)
    {
        x=rand();
        x=x/RAND_MAX;
        if (x < Prob)
        {
            array[j]=1;
        }
        else
        {
            array[j]=0;
        }
    }

/* Print the sum of ones in the array
 * in order to check the rand_gen probability
 * reliability and compare to the bin_array_*   */
    sum = sum_array(array, N);
    printf("\n The sum of the temp array is %d\n", sum);

    return array;
}


// Function: sum elements of array and return the sum.
int sum_array(int a[], int num_elements)
{
    int k, sum=0;
    for (k=0; k<num_elements; k++)
        {
        sum = sum + a[k];
        }
    return(sum);
}

Please give me some tips how to solve the issue. I have already tried with different types of values (long instead of int and double instead of float) but without any result. Thank you in advance!

Cheers,

Pullo86

回答1:

What you almost certainly want to do is pass rand_gen() a pointer to the array it’s to be filling, and have it write to that, rather than have it allocate large arrays which it then copies and leaks. (This is an application for which the C++ STL, with <random> and <vector>, might be better-suited.)

If you want to use this basic structure, though, declare:

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

/* Set N. */

bool *binarray[] = {
  rand_gen( N, prob_a ), // binarray[0]
  rand_gen( N, prob_a ), 
  rand_gen( N, prob_a ),
  rand_gen( N, prob_a )  // binarray[3]
};
static const size_t m = sizeof(binarray)/sizeof(binarray[0]);

/* Do stuff with binarray[0] through binarray[m-1]. */

for ( size_t i = 0; i < m; ++i ) {
  free(binarray[i]);
  binarray[i] = NULL;
}

In practice, though, you probably want an array of arrays that your random generator updates in place, something like:

bool *fill_arrays( size_t m, size_t n, bool to_fill[m][n], double prob )
{
  for ( size_t i = 0; i < m; ++i )
    rand_gen_in_place( to_fill[i], n, prob );

  return to_fill;
}

void do_stuff_with( size_t m, size_t n, bool binarray[m][n] );

int main(void)
{
  /* … */
  bool* arrayp = calloc( M*N, sizeof(bool) );
  fill_arrays( M, N, arrayp, prob_a );
  do_stuff_with( M, N, arrayp );
  free(arrayp);
  /* … */
}