【问题标题】:How to generate uniform single precision floating point random number between 0 and 1 in FPGA?如何在FPGA中生成0到1之间的统一单精度浮点随机数?
【发布时间】:2021-06-05 19:42:15
【问题描述】:

我正在尝试通过生成 0 到 0x3f80000 之间的数字(IEEE 格式为 1)使用 FPGA 生成单精度浮点随机数。但是由于接近零的离散点数量多于 1,因此我没有得到统一的生成。是否有任何转换可以应用于模拟统一生成。我正在使用 LFSR(32 位)和 Xoshiro 随机数生成。

【问题讨论】:

  • 显然这是一个热门的研究课题。谷歌single precision uniform random 并选择。或者您可以从一个常数指数开始,并将小数部分生成为一个随机整数。这主要会产生次正规数,因此您可能需要在之后重新规范化它们。

标签: random verilog fpga number-theory randomized-algorithm


【解决方案1】:

请在此处查看 xoshiro128+ https://prng.di.unimi.it/xoshiro128plus.c

有人写的VHDL代码可以在这里找到: https://github.com/jorisvr/vhdl_prng/tree/master/rtl

种子值是从另一个随机数生成算法生成的,所以不要被这个弄糊涂了。

根据使用的种子值,它应该给出均匀分布。

【讨论】:

    【解决方案2】:

    从均匀分布的 32 位无符号整数生成 [0,1) 中均匀分布的floats 的标准方法是将整数乘以 2-32。显然,我们不会为了这个目的而在 FPGA 上实例化一个浮点乘法器,我们也不必这样做,因为乘法器是 2 的幂。本质上,需要将整数转换为浮点数,然后将浮点数的指数递减 32。这对于必须作为特殊情况处理的零输入不起作用。在下面的 ISO-C99 代码中,我假设 float 映射到 IEEE-754 binary32 类型。

    除了某些特殊情况外,IEEE-754 二进制浮点数的有效位被标准化为 [1,2)。要将整数转换为有效数字,我们需要对其进行归一化,因此设置了最高有效位。我们可以通过计算前导零位的数量,然后将数字左移该数量来做到这一点。调整指数也需要前导零的计数。

    binary32 数的有效位由 24 位组成,其中仅存储 23 位;最高有效位(整数位)始终为 1,因此是隐含的。这意味着并非整数的所有 32 位都可以合并到 binary32 中,因此在将 32 位无符号整数转换为 24 位精度时,通常 rounds。为了简化实现,在下面的代码中,我只是通过切断最低有效八位来截断,这对均匀分布应该没有明显的影响。对于指数部分,我们可以将归一化步骤的调整与比例因子 2-32 的减法相结合。

    下面的代码是使用以硬件为中心的原语编写的。提取一点只是抓住正确线的问题,固定数量的移位同样简单的线移位。需要计算前导零个数的电路通常称为优先级编码器。

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    #define USE_FP_MULTIPLY  (0)
    
    uint32_t bit (uint32_t, uint32_t);
    uint32_t mux (uint32_t, uint32_t, uint32_t);
    uint32_t clz (uint32_t);
    float uint32_as_float (uint32_t);
    
    /* uniform float in [0, 1) from uniformly distributed random integers */
    float uniform_rand_01 (uint32_t i)
    {
        const uint32_t FP32_EXPO_BIAS = 127;
        const uint32_t FP32_MANT_BITS = 24;
        const uint32_t FP32_STORED_MANT_BITS = FP32_MANT_BITS - 1;
        uint32_t lz, r;
    
        // compute shift amount needed for normalization
        lz = clz (i);
        // normalize so that msb is set, except when input is zero
        i = mux (bit (lz, 4), i << 16, i);
        i = mux (bit (lz, 3), i <<  8, i);
        i = mux (bit (lz, 2), i <<  4, i);
        i = mux (bit (lz, 1), i <<  2, i);
        i = mux (bit (lz, 0), i <<  1, i);
        // build bit pattern for IEEE-754 binary32 floating-point number
        r = (((FP32_EXPO_BIAS - 2 - lz) << FP32_STORED_MANT_BITS) + 
             (i >> (32 - FP32_MANT_BITS)));
        // handle special case of zero input
        r = mux (i == 0, i, r);
        // treat bit-pattern as 'float'
        return uint32_as_float (r);
    }
    
    // extract bit i from x
    uint32_t bit (uint32_t x, uint32_t i)
    {
        return (x >> i) & 1;
    }
    
    // simulate 2-to-1 multiplexer: c ? a : b ; c must be in {0,1}
    uint32_t mux (uint32_t c, uint32_t a, uint32_t b)
    {
        uint32_t m = c * 0xffffffff;
        return (a & m) | (b & ~m);
    }
    
    // count leading zeros. A priority encoder in hardware.
    uint32_t clz (uint32_t x)
    {
        uint32_t m, c, y, n = 32;
    
        y = x >> 16; m = n - 16; c = (y != 0); n = mux (c, m, n); x = mux (c, y, x);
        y = x >>  8; m = n -  8; c = (y != 0); n = mux (c, m, n); x = mux (c, y, x);
        y = x >>  4; m = n -  4; c = (y != 0); n = mux (c, m, n); x = mux (c, y, x);
        y = x >>  2; m = n -  2; c = (y != 0); n = mux (c, m, n); x = mux (c, y, x);
        y = x >>  1; m = n -  2; c = (y != 0); n = mux (c, m, n - x);
        return n;
    }
    
    // re-interpret bit pattern of a 32-bit integer as an IEEE-754 binary32 
    float uint32_as_float (uint32_t a)
    {
        float r;
        memcpy (&r, &a, sizeof r);
        return r;
    }
    
    // George Marsaglia's KISS PRNG, period 2**123. Newsgroup sci.math, 21 Jan 1999
    // Bug fix: Greg Rose, "KISS: A Bit Too Simple" http://eprint.iacr.org/2011/007
    static uint32_t kiss_z=362436069, kiss_w=521288629;
    static uint32_t kiss_jsr=123456789, kiss_jcong=380116160;
    #define znew (kiss_z=36969*(kiss_z&65535)+(kiss_z>>16))
    #define wnew (kiss_w=18000*(kiss_w&65535)+(kiss_w>>16))
    #define MWC  ((znew<<16)+wnew )
    #define SHR3 (kiss_jsr^=(kiss_jsr<<13),kiss_jsr^=(kiss_jsr>>17), \
                  kiss_jsr^=(kiss_jsr<<5))
    #define CONG (kiss_jcong=69069*kiss_jcong+1234567)
    #define KISS ((MWC^CONG)+SHR3)
    
    #define N 100
    
    uint32_t bucket [N];
    
    int main (void)
    {
        for (int i = 0; i < 100000; i++) {
            uint32_t i = KISS;
    #if USE_FP_MULTIPLY
            float r = i * 0x1.0p-32f;
    #else // USE_FP_MULTIPLY
            float r = uniform_rand_01 (i);
    #endif // USE_FP_MULTIPLY
            bucket [(int)(r * N)]++;
        }
        for (int i = 0; i < N; i++) {
            printf ("bucket [%2d]: [%.5f,%.5f): %u\n", 
                    i, 1.0f*i/N, (i+1.0f)/N, bucket[i]);
        }
        return EXIT_SUCCESS;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-07
      • 2014-09-22
      • 2012-12-17
      • 1970-01-01
      • 2014-04-11
      • 1970-01-01
      • 2017-10-22
      相关资源
      最近更新 更多