%% Create Predictable Arrays of Random Numbers on the GPU and CPU
% Capture the GPU generator settings, and set the state of the CPU random number generator to match the GPU generator settings. Create predictable arrays of random numbers on the CPU and GPU.
%
% Restore the generator type and seed to their default values on both the CPU and the GPU.

gpurng('default') 
rng('default')

% Save the default seed and generator type of the GPU random number generator.

GPUdef = gpurng

% Set the CPU random number generator to match the default GPU settings.

rng(GPUdef) 

%
% Create an array of uniformly distributed random numbers on the GPU.

rGPU = rand(1,10, 'gpuArray')

% Create an array of random numbers on the CPU.

rCPU = rand(1,10)

% The seed and generator type are the same for both the GPU and the CPU, so the arrays are the same.

isequal(rGPU,rCPU)

%
% The gpurng state does not save the settings for the transformation applied to generate a normally distributed set of random numbers. Even though the seed and the generator type are the same on the GPU and the CPU, the set of normally distributed random numbers is different.

nGPU = randn(1,1000, 'gpuArray');
nCPU = randn(1,1000);

figure
hold on
histogram(nGPU)
histogram(nCPU)
legend('GPU','CPU')
title('Normally Distributed Random Numbers')
xlabel('Value')
ylabel('Count')
hold off

% The statistics of the normal distribution of random numbers are the same on the GPU and the CPU.
% By default, the CPU uses the 'Ziggurat' transformation, while the GPU uses the 'BoxMuller' algorithm for the 'Threefry' generator. The only transformation method supported on both the CPU and GPU is the 'Inversion' transform.
% You can change the transformation method on the GPU using parallel.gpu.RandStream.
% Copyright 2018 The MathWorks, Inc.