首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用OpenCL的Random123随机数

使用OpenCL的Random123随机数
EN

Stack Overflow用户
提问于 2012-06-29 19:44:04
回答 3查看 2.9K关注 0票数 3

我一直在查看这个库Random123和相关的引用:

一个神秘的人来到我的展位,问我对用OpenCL生成随机数知道些什么。我告诉了他关于Mersenne Twister的实现,但他并没有留下深刻的印象。他告诉我一篇新的技术论文,它解释了如何结合整数计数器和块密码在GPU上生成随机数。他以崇敬的语气说,反基随机数发生器(CBRNGs)产生的数字比MT具有更大的统计随机性,而且速度更快。

我能够使用这个内核获得一个运行演示:

代码语言:javascript
运行
复制
__kernel void counthits(unsigned n, __global uint2 *hitsp) {
    unsigned tid = get_global_id(0);
    unsigned hits = 0, tries = 0;
    threefry4x32_key_t k = {{tid, 0xdecafbad, 0xfacebead, 0x12345678}};
    threefry4x32_ctr_t c = {{0, 0xf00dcafe, 0xdeadbeef, 0xbeeff00d}};
    while (tries < n) {
        union {
            threefry4x32_ctr_t c;
            int4 i;
        } u;
        c.v[0]++;
        u.c = threefry4x32(c, k);
        long x1 = u.i.x, y1 = u.i.y;
        long x2 = u.i.z, y2 = u.i.w;
        if ((x1*x1 + y1*y1) < (1L<<62)) {
            hits++;
        }
        tries++;
        if ((x2*x2 + y2*y2) < (1L<<62)) {
            hits++;
        }
        tries++;
    }
    hitsp[tid].x = hits;
    hitsp[tid].y = tries;
}

我现在的问题是,这会不会产生相同的随机数每次运行,一个随机数是基于全局id?我怎么能每次都生成新的随机数。可以为内核提供一个种子作为参数,然后以某种方式使用它吗?

有谁使用过这个库,并能给我更多的关于使用它的洞察力吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-02 16:06:01

是。该示例代码在每次调用时都生成相同的随机数序列。

要获得不同的随机数流,只需以不同的方式初始化任意值K1.3和/或c1..3。您可以通过命令行参数、环境变量、每日时间、保存状态、/dev/urandom或任何其他源来初始化它们。只是要意识到:

( a)如果在两次不同的运行中以完全相同的方式初始化它们,那么这两次运行将得到相同的随机数流。

如果在两次不同的运行中对它们进行不同的初始化,那么这两次运行将得到不同的随机数流。

有时你想要财产a)。有时你想要财产b)。花点时间想想你想要什么,并确保你正在做你想做的事情。

更普遍地说,库中的函数(例如threefry4x32 )具有无状态。如果您更改输入中的任何位(即c或k的任何元素中的任何位),则会得到完全不同的随机、统计独立、均匀分布的输出。

P.S.我是该图书馆的作者之一,论文“并行数字:和1,2,3一样容易”:http://dl.acm.org/citation.cfm?id=2063405

如果您不是ACM数字图书馆的订阅者,上面的链接可能会碰到付费墙。或者,您可以通过以下链接免费获得纸张:

http://www.thesalmons.org/john/random123/index.html

票数 5
EN

Stack Overflow用户

发布于 2012-07-01 21:23:25

我无法帮助您处理库本身,但我可以告诉您,在OpenCL中生成随机数的最常见方法是在调用内核之间保存一些状态。

随机数发生器通常使用一种状态,由此生成一个新的状态和一个随机数。实际上,这一点也不复杂:您只需传递一个包含状态的额外数组。在我的代码中,我实现了以下随机数:

代码语言:javascript
运行
复制
uint rand_uint(uint2* rvec) {  //Adapted from http://cas.ee.ic.ac.uk/people/dt10/research/rngs-gpu-mwc64x.html
    #define A 4294883355U
    uint x=rvec->x, c=rvec->y; //Unpack the state
    uint res = x ^ c;          //Calculate the result
    uint hi = mul_hi(x,A);     //Step the RNG
    x = x*A + c;
    c = hi + (x<c);
    *rvec = (uint2)(x,c);      //Pack the state back up
    return res;                //Return the next result
    #undef A
}
inline float rand_float(uint2* rvec) {
    return (float)(rand_uint(rvec)) / (float)(0xFFFFFFFF);
}
__kernel void my_kernel(/*more arguments*/ __global uint2* randoms) {
    int index = get_global_id(0);
    uint2 rvec = randoms[index];

    //Call rand_uint or rand_float a number of times with "rvec" as argument.
    //These calls update "rvec" with new state, and return a random number

    randoms[index] = rvec;
}

。。。然后,您所要做的就是传递一个额外的数组,该数组将RNG的状态随机保存起来。实际上,您需要为每个工作项设置不同的数组种子。

票数 2
EN

Stack Overflow用户

发布于 2012-09-02 20:11:45

0xdecafbad0xfacebead0x123456780xf00dcafe0xdeadbeef0xbeeff00d只是任意选择的数字,它们不是特殊的。任何其他数字(甚至0)都可以用来代替它们--我将在示例代码中添加一个注释。

您可以用传入的变量替换它们中的任何一个;在输出随机“流”中避免不必要的重复的唯一要求是避免重复(c,k)输入元组。示例代码使用线程id和循环索引来确保唯一性,但您可以轻松地添加更多变量以确保唯一性--例如,在主机代码中计算内核调用并传入计数器,使用它代替k或c的元素之一。

顺便说一句,尽管名字是“基于计数器的随机数生成器”,但没有要求输入(c,k)是“计数器”,只是计数器恰好是确保输入不重复的最方便的成语。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11268023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档