The cuRAND device function library

Let's start with cuRAND. This is a standard CUDA library that is used for generating pseudo-random values within a CUDA kernel on a thread-by-thread basis, which is initialized and invoked by calling device functions from each individual thread within a kernel. Let's emphasize again that this is a pseudo-random sequence of values—since the digital hardware is always deterministic and never random or arbitrary, we use algorithms to generate a sequence of apparently random values from an initial seed value. Usually, we can set the seed value to a truly random value (such as the clock time in milliseconds), which will yield us with a nicely arbitrary sequence of random values. These generated random values have no correlation with prior or future values in the sequence generated by the same seed, although there can be correlations and repeats when you combine values generated from different seeds. For this reason, you have to be careful that the values you wish to be mutually random are generated by the same seed.

Let's start by looking at the function prototype for curand_init, which we will initialize with an appropriate seed:

__device__ void curand_init ( unsigned long long seed, unsigned long long sequence, unsigned long long offset, curandState_t *state)

Here, all of the inputs are unsigned long, which in C is an unsigned (non-negative valued) 64-bit integer. First, we can see the seed, which is, of course, the seed value. Generally speaking, you'll set this with the clock value or some variation. We then see a value called sequence and as we stated previously, values generated by cuRAND will only be truly mathematically mutually random if they are generated by the same seed value. So, if we have multiple threads using the same seed value, we use sequence to indicate which sub-sequence of random numbers of length 2190 for the current thread to use, while we use offset to indicate at which point to start within this sub-sequence; this will generate values in each thread that are all mathematically mutually random with no correlation. Finally, the last parameter is for a pointer to a curandState_t object; this keeps track of where we are in the sequence of pseudo-random numbers.

After you initialize a class object, you will then generate random values from the appropriate random distribution by calling the appropriate device function. The two most common distributions are uniform and normal (Gaussian). A uniform distribution (curand_uniform, in cuRAND) is a function that outputs values that are all equally probable over a given range: that is to say, for a uniform distribution over 0 to 1, there is a 10% chance that a value will fall between 0 and 0.1, or between 0.9 to 1, or between any two points that are spaced .1 away from each other. The normal distribution (curand_normal, in cuRAND) has values that are centered at a particular mean, which will be distributed according to the well-known bell-shaped curve that is defined by the distribution's standard deviation. (The default mean of curand_normal is 0 and the standard deviation is 1 in cuRAND, so this will have to be shifted and scaled manually for other values.) Another well-known distribution supported by cuRAND is the Poisson distribution (curand_poisson), which is used for modeling the occurrences of random events over time.

We will be primarily looking at how to use cuRAND in the context of uniform distributions in the next section, due to their applicability to Monte Carlo integration. Readers interested in learning how to use more features in cuRAND are encouraged to look at the official documentation from NVIDIA.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.88.157