duttasankha
duttasankha

Reputation: 737

Generating random number in cuda kernel between 0 and 1

I have a cuda application where I want to generate random numbers between 0 and 1. I have written a dummy code where a matrix of size 8x256 would be filled up by random numbers generated by kernel. My original matrix would be something like 8XBIG_NUMBER. But probably I am missing something in my code because of which I am not able to produce the desired result.I am posting my code below.

void main(int argc,char* argv[])    
{
    float *test_var,*dev_test;
    curandState *state;

    test_var = (float *)malloc(8*256*sizeof(float));
    memset(test_var,0,8*256*sizeof(float));

    cudaMalloc((void **)&dev_test,8*256*sizeof(float));
    cudaMemcpy(dev_test,test_var,8*256*sizeof(float),cudaMemcpyHostToDevice);
    dim3 gridDim(1,256/32,1);
    dim3 blockDim(8,32,1);
    cudaMalloc((void **)&state,8*256*sizeof(curandState));
    setup_kernel<<<gridDim,blockDim>>>(state,unsigned(time(NULL)));
    test_kernel<<<gridDim,blockDim>>>(state,dev_test);
    cudaMemcpy(test_var,dev_test,8*256*sizeof(float),cudaMemcpyDeviceToHost);
    system("PAUSE");

    for (int i=0;i<256;i++)
    {   for (int j=0;j<8;j++)
        { printf("%f\t",test_var[i*8+j]);
        }
        printf("\n");
    }

    cudaFree(dev_test);
    cudaFree(state);
    free(test_var);
    exit(0);
}

__global__ void setup_kernel(curandState *state,unsigned long seed)
{
    int id_col  = threadIdx.x + blockDim.x*blockIdx.x;
    int id_row = threadIdx.y+blockDim.y*blockIdx.y;

    curand_init(seed,(id_row*8+id_col),0,&state[id_row*8+id_col]);
}

__global__ void test_kernel(curandState *state,float *dev_test)
{
    int id_col  = threadIdx.x + blockDim.x*blockIdx.x;
    int id_row = threadIdx.y+blockDim.y*blockIdx.y;

     curandState local_state = state[id_row*8+id_col];
     dev_test[id_row*8+id_col] = curand(&local_state);   
     state[id_row*8+id_col] = local_state;
}

I want to generate a random number between 0 and 1 for each of those cells in the matrix. I would really appreciate of anyone's assistance. Thank you

Upvotes: 1

Views: 4793

Answers (1)

Robert Crovella
Robert Crovella

Reputation: 151829

If you refer to the curand documentation, you'll note the declaration given for the device api function you are using:

__device__ unsigned int curand (curandState_t *state)

This particular API call returns an unsigned int. So you're not going to get floating point values unless you modify it somehow.

Since it returns unsigned int values, one possible modification would simply be to scale the result:

 dev_test[id_row*8+id_col] = curand(&local_state)/(float)(0x0FFFFFFFFUL);

This modification should give you floating point values between 0 and 1. However this is rather crude for a variety of reasons. As suggested in the comments, it makes more sense to select one of the device generators that will do this for you, such as:

 dev_test[id_row*8+id_col] = curand_uniform(&local_state);

I'm not an expert on this, but it seems that a multinomial distribution is fundamentally a discrete distribution. Therefore, you will need some method to convert a continuous-valued distribution to a discrete one, if you intend to start with floating point random numbers between 0 and 1. Wikipedia gives a method for doing this starting with continuous-valued random numbers between 0 and 1, and based on my read of that method, the curand_uniform distribution/generator would be a reasonable starting point.

Upvotes: 4

Related Questions