Имеется набор генераторов случайных чисел, которые возвращают целочисленные значения, распределенные в соответствии со стандартными функциями распределения вероятности.
17.9.1. $random
Синтаксис системной функции $random показан в Синтаксисе 17-17.
random_function ::=
$random [ ( seed ) ]
$random — это системная функция, которая предоставляет механизм для генерации случайных чисел. При каждом вызове функция возвращает новое 32-битное случайное число. Случайное число является знаковым целым числом. Оно может быть положительным или отрицательным. Более подробную информацию о вероятностных генераторах случайных чисел смотрите в разделе 17.9.2.
Аргумент seed управляет числами, которые возвращает $random, так что разные seed генерируют разные случайные потоки. Аргумент seed должен быть либо reg, либо целым числом, либо временной переменной. Значение seed должно быть присвоено этой переменной до вызова $random.
Например:
Пример 1 — Если b больше 0, то выражение ($random % b) дает число в следующем диапазоне: [(-b+1): (b-1)].
reg [23:0] rand;
rand = $random % 60;
reg [23:0] rand;
rand = {$random} % 60;
17.9.2. $dist_
Синтаксис для вероятностных функций распределения показан в Синтаксисе 17-18.
dist_functions ::=
$dist_uniform ( seed , start , end )
| $dist_normal ( seed , mean , standard_deviation )
| $dist_exponential ( seed , mean )
| $dist_poisson ( seed , mean )
| $dist_chi_square ( seed , degree_of_freedom )
| $dist_t ( seed , degree_of_freedom )
| $dist_erlang ( seed , k_stage , mean )
Все аргументы системных функций являются целочисленными значениями. Для функций exponential, poisson, chi-square, t и erlang аргументы mean, degree_of_freedom и k_stage должны быть больше 0.
Каждая из этих функций возвращает псевдослучайное число, характеристики которого описываются именем функции. Другими словами, $dist_uniform(Непрерывное равномерное распределение) возвращает случайные числа, равномерно распределенные в интервале, заданном ее аргументами.
Для каждой системной функции аргумент seed является аргументом inout. Т.е. в функцию передается значение, а возвращается другое значение. Функции системы должны всегда возвращать одно и то же значение при одном и том же seed. Это облегчает отладку, делая работу системы повторяемой. Аргумент seed должен быть целочисленной переменной, которая инициализируется пользователем и обновляется только системной функцией. Это гарантирует достижение желаемого распределения.
В функции $dist_uniform(Непрерывное равномерное распределение) аргументы start и end являются целочисленными значениями, которые ограничивают возвращаемые значения. Начальное значение должно быть меньше конечного.
Аргумент mean, используемый $dist_normal(нормальное распределение), $dist_exponential(экспоненциальное распределение), $dist_poisson(распределение Пуассона) и $dist_erlang(распределение Ерланга), представляет собой целочисленный вход, который заставляет среднее значение, возвращаемое функцией, приближаться к указанному значению.
Аргумент standard_deviation, используемый с функцией $dist_normal, является целочисленным параметром, который помогает определить форму функции плотности. Большие числа для стандартного отклонения распределяют возвращаемые значения по более широкому диапазону.
Аргумент degree_of_freedom, используемый с функциями $dist_chi_square(распределение хи-квадрат) и $dist_t, является целочисленным значением, которое помогает определить форму функции плотности. Большие числа распределяют возвращаемые значения по более широкому диапазону.
17.9.3. Алгоритм для функций распределения вероятностей
В таблице 17-17 перечислены функции вероятностного распределения Verilog с соответствующими функциями на языке C.
Таблица 17.17 Перекрестный список функций Verilog на C
Функция Verilog | Функция C |
---|---|
$dist_uniform | rtl_dist_uniform |
$dist_normal | rtl_dist_normal |
$dist_exponential | rtl_dist_exponential |
$dist_poisson | rtl_dist_poisson |
$dist_chi_square | rtl_dist_chi_square |
$dist_t | rtl_dist_t |
$dist_erlang | rtl_dist_erlang |
$random | rtl_dist_uniform (seed, LONG_MIN, LONG_MAX) |
/*
* Algorithm for probabilistic distribution functions.
*
* IEEE Std 1364-2005 Verilog Hardware Description Language (HDL)
*/
#include <limits.h>
static double uniform( long *seed, long start, long end );
static double normal( long *seed, long mean, long deviation);
static double exponential( long *seed, long mean);
static long poisson( long *seed, long mean);
static double chi_square( long *seed, long deg_of_free);
static double t( long *seed, long deg_of_free);
static double erlangian( long *seed, long k, long mean);
long rtl_dist_chi_square( seed, df )
long *seed;
long df;
{
double r;
long i;
if(df>0)
{
r=chi_square(seed,df);
if(r>=0)
{
i=(long)(r+0.5);
}
else
{
r = -r;
i=(long)(r+0.5);
i = -i;
}
}
else
{
print_error("WARNING: Chi_square distribution must ",
"have positive degree of freedom\n");
i=0;
}
return (i);
}
long rtl_dist_erlang( seed, k, mean )
long *seed;
long k, mean;
{
double r;
long i;
if(k>0)
{
r=erlangian(seed,k,mean);
if(r>=0)
{
i=(long)(r+0.5);
}
else
{
r = -r;
i=(long)(r+0.5);
i = -i;
}
}
else
{
print_error("WARNING: k-stage erlangian distribution ",
"must have positive k\n");
i=0;
}
return (i);
}
long rtl_dist_exponential( seed, mean )
long *seed;
long mean;
{
double r;
long i;
if(mean>0)
{
r=exponential(seed,mean);
if(r>=0)
{
i=(long)(r+0.5);
}
else
{
r = -r;
i=(long)(r+0.5);
i = -i;
}
}
else
{
print_error("WARNING: Exponential distribution must ",
"have a positive mean\n");
i=0;
}
return (i);
}
long rtl_dist_normal( seed, mean, sd )
long *seed;
long mean, sd;
{
double r;
long i;
r=normal(seed,mean,sd);
if(r>=0)
{
i=(long)(r+0.5);
}
else
{
r = -r;
i=(long)(r+0.5);
i = -i;
}
return (i);
}
long rtl_dist_poisson( seed, mean )
long *seed;
long mean;
{
long i;
if(mean>0)
{
i=poisson(seed,mean);
}
else
{
print_error("WARNING: Poisson distribution must have a ",
"positive mean\n");
i=0;
}
return (i);
}
long rtl_dist_t( seed, df )
long *seed;
long df;
{
double r;
long i;
if(df>0)
{
r=t(seed,df);
if(r>=0)
{
i=(long)(r+0.5);
}
else
{
r = -r;
i=(long)(r+0.5);
i = -i;
}
}
else
{
print_error("WARNING: t distribution must have positive ",
"degree of freedom\n");
i=0;
}
return (i);
}
long rtl_dist_uniform(seed, start, end)
long *seed;
long start, end;
{
double r;
long i;
if (start >= end) return(start);
if (end != LONG_MAX)
{
end++;
r = uniform( seed, start, end );
if (r >= 0)
{
i = (long) r;
}
else
{
i = (long) (r-1);
}
if (i<start) i = start;
if (i>=end) i = end-1;
}
else if (start!=LONG_MIN)
{
start--;
r = uniform( seed, start, end) + 1.0;
if (r>=0)
{
i = (long) r;
}
else
{
i = (long) (r-1);
}
if (i<=start) i = start+1;
if (i>end) i = end;
}
else
{
r =(uniform(seed,start,end)+
2147483648.0)/4294967295.0);
r = r*4294967296.0-2147483648.0;
if (r>=0)
{
i = (long) r;
}
else
{
i = (long) (r-1);
}
}
return (i);
}
static double uniform( seed, start, end )
long *seed, start, end;
{
union u_s
{
float s;
unsigned stemp;
} u;
double d = 0.00000011920928955078125;
double a,b,c;
if ((*seed) == 0)
*seed = 259341593;
if (start >= end)
{
a = 0.0;
b = 2147483647.0;
}
else
{
a = (double) start;
b = (double) end;
}
*seed = 69069 * (*seed) + 1;
u.stemp = *seed;
/*
* This relies on IEEE floating point format
*/
u.stemp = (u.stemp >> 9) | 0x3f800000;
c = (double) u.s;
c = c+(c*d);
c = ((b - a) * (c - 1.0)) + a;
return (c);
}
static double normal(seed,mean,deviation)
long *seed,mean,deviation;
{
double v1,v2,s;
double log(), sqrt();
s = 1.0;
while ((s >= 1.0) || (s == 0.0))
{
v1 = uniform(seed,-1,1);
v2 = uniform(seed,-1,1);
s = v1 * v1 + v2 * v2;
}
s = v1 * sqrt(-2.0 * log(s) / s);
v1 = (double) deviation;
v2 = (double) mean;
return(s * v1 + v2);
}
static double exponential(seed,mean)
long *seed,mean;
{
double log(),n;
n = uniform(seed,0,1);
if(n != 0)
{
n = -log(n) * mean;
}
return(n);
}
static long poisson(seed,mean)
long *seed,mean;
{
long n;
double p,q;
double exp();
n = 0;
q = -(double)mean;
p = exp(q);
q = uniform(seed,0,1);
while(p < q)
{
n++;
q = uniform(seed,0,1) * q;
}
return(n);
}
static double chi_square(seed,deg_of_free)
long *seed,deg_of_free;
{
double x;
long k;
if(deg_of_free % 2)
{
x = normal(seed,0,1);
x = x * x;
}
else
{
x = 0.0;
}
for(k = 2; k <= deg_of_free; k = k + 2)
{
x = x + 2 * exponential(seed,1);
}
return(x);
}
static double t(seed,deg_of_free)
long *seed,deg_of_free;
{
double sqrt(),x;
double chi2 = chi_square(seed,deg_of_free);
double div = chi2 / (double)deg_of_free;
double root = sqrt(div);
x = normal(seed,0,1) / root;
return(x);
}
static double erlangian(seed,k,mean)
long *seed,k,mean;
{
double x,log(),a,b;
long i;
x=1.0;
for(i=1;i<=k;i++)
{
x = x * uniform(seed,0,1);
}
a=(double)mean;
b=(double)k;
x= -a*log(x)/b;
return(x);
}