Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How good are VHDL's random numbers?

I'm using VHDL's random numbers from IEEE.math_real, but how good are these generated numbers?

.... let's say compared to rand(...) from C.

Have there been statistical tests?


Here is a histogram of a Gaussian distribution. Parameters:

  • Random source: 2 uniform distributed REAL values generated by math_real.Uniform(...)
  • Box-Muller transformation
  • calculated using REAL
  • Output rang: 0..4095 INTEGER
  • 102.400 iterations

Classic histogram view:
NormalDistributedRandomValue 100Ki iterations; range 0..4095

As a point cloud:
NormalDistributedRandomValue 100Ki iterations; range 0..4095


Here is a histogram of a uniform distribution. Parameters:

  • Random source: uniform distributed REAL values generated by math_real.Uniform(...)
  • calculated using REAL
  • Output rang: 0..4095 INTEGER
  • 102.400 iterations

Classic histogram view:
NormalDistributedRandomValue 100Ki iterations; range 0..4095

As a point cloud:
NormalDistributedRandomValue 100Ki iterations; range 0..4095

Gnuplot fitting results for f(x)=m*x+b:

m = -0.0000343906
b = 25.0704

In my opinion, both histograms have a high jitter.

like image 728
Paebbels Avatar asked Oct 30 '22 09:10

Paebbels


1 Answers

The implementation of IEEE.math_real.UNIFORM is:

procedure UNIFORM(variable SEED1,SEED2:inout POSITIVE;variable X:out REAL) is
  ...
  variable Z, K: INTEGER;
  variable TSEED1 : INTEGER := INTEGER'(SEED1);
  variable TSEED2 : INTEGER := INTEGER'(SEED2);
begin
  ...

  K := TSEED1 / 53668;
  TSEED1 := 40014 * (TSEED1 - K * 53668) - K * 12211;
  if TSEED1 < 0  then
    TSEED1 := TSEED1 + 2147483563;
  end if;

  K := TSEED2 / 52774;
  TSEED2 := 40692 * (TSEED2 - K * 52774) - K * 3791;
  if TSEED2 < 0  then
    TSEED2 := TSEED2 + 2147483399;
  end if;

  Z := TSEED1 - TSEED2;
  if Z < 1 then
    Z := Z + 2147483562;
  end if;

  SEED1 := POSITIVE'(TSEED1);
  SEED2 := POSITIVE'(TSEED2);
  X :=  REAL(Z) * 4.656613e-10;
end UNIFORM;

With these description about implementation:

a) The semantics for this function are described by the algorithm published by Pierre L'Ecuyer in "Communications of the ACM," vol. 31, no. 6, June 1988, pp. 742-774. The algorithm is based on the combination of two multiplicative linear congruential generators for 32-bit platforms.

b) Before the first call to UNIFORM, the seed values (SEED1, SEED2) have to be initialized to values in the range [1, 2147483562] and [1, 2147483398] respectively. The seed values are modified after each call to UNIFORM.

c) This random number generator is portable for 32-bit computers, and it has a period of ~2.30584*(10**18) for each set of seed values.

d) For information on spectral tests for the algorithm, refer to the L'Ecuyer article.

The L'ecuyer paper is "Efficient and portable combined random number generators", as given by user1155120 in the comments.

So it is a Combined Linear Congruential Generator (CLCG) using Wichmann/Hill/Schrage/Bratley et. al.'s method (see L'ecuyer paper) to avoid integer overflow when implemented using 32-bit integers.

It appears that the constants selected for the CLCG are well known, based on the Wiki and other references I could find by quick search. As user1155120 informs in the comments, the random properties of the CLCG have been analyzed in "A Comparison of Four Pseudo Random Number Generators Implemented in Ada".

Based on this, it appears that the VHDL random generator is pretty solid, so I would expect that the jitter/outliers that you found are simply a result of the randomness.

like image 89
Morten Zilmer Avatar answered Nov 16 '22 16:11

Morten Zilmer