使用RAND()以产生上均匀分布的浮点数(A,B),[A,B),(A,B]和[A,B](Use ra

2019-06-28 00:36发布

我要领取“最佳”的方式在一个地方产生对所有四种类型的间隔的随机数。 我生病了谷歌搜索这一点。 搜索结果带来很多的废话。 即使是相关的结果是往往是完全错误或有讨论,有自封的专家彼此之间通过一些技术性不同意,经常与自己的“答案”似乎揭露,他们不知道不同类型的网页或博客(关闭,开放的,间隔的半开放式)。 我生病的阅读产生用C的随机数这样一个“简单”的问题,不良信息。

请告诉我如何产生均匀分布浮点数。 下面是(使用 “长双” 作为例子)我的典型方法是(a,b)中,[A,B),(A,B]和[A,B]:

long double a=VALUE1,b=VALUE2;
long double x1,x2,x3,x4;

srand((unsigned)time(NULL));

/* x1 will be an element of [a,b] */
x1=((long double)rand()/RAND_MAX)*(b-a) + a;

/* x2 will be an element of [a,b) */
x2=((long double)rand()/((long double)RAND_MAX+1))*(b-a) + a;

/* x3 will be an element of (a,b] */
x3=(((long double)rand()+1)/((long double)RAND_MAX+1))*(b-a) + a;

/* x4 will be an element of (a,b) */    
x4=(((long double)rand()+1)/((long double)RAND_MAX+2))*(b-a) + a;

为单位的时间间隔的特殊情况下(0,1),[0,1),(0,1]和[0,1]:

long double x1,x2,x3,x4;

srand((unsigned)time(NULL));

/* x1 will be an element of [0,1] */
x1=((long double)rand()/RAND_MAX);

/* x2 will be an element of [0,1) */
x2=((long double)rand()/((long double)RAND_MAX+1));

/* x3 will be an element of (0,1] */
x3=(((long double)rand()+1)/((long double)RAND_MAX+1));

/* x4 will be an element of (0,1) */    
x4=(((long double)rand()+1)/((long double)RAND_MAX+2));

我相信,双方RAND_MAX石膏和RAND()的返回值是必要的,这不仅是因为我们要避免整数除法,而是因为他们是整数否则增加一个(或两个)可能会溢出他们。

我觉得版本的“双”和“浮动”是完全一样的,但只是更换型。 是否有出现的不同的浮点类型的任何细微之处?

你看到上述实现的任何问题? 如果是这样,什么,你将如何解决这个问题?

编辑:上述实施方式中通过对他们来说是正确的(至少在运行64位Linux 64位英特尔酷睿2机器上)必要的测试:X1可以产生0和1,X 2可以产生0但尚未可见,以产生如图1所示,X 3可以产生1,但还没有被看到,以生成0,和x4已经不明显产生0或1。

Answer 1:

如果你想在每一个范围内双是可能的,概率成正比,它和它相邻的双重价值之间的差异,那么它实际上真的很难。

考虑范围[0, 1000] 有值的范围内的非常小的第一部分绝对bucketload:它们之间的百万01000000*DBL_MINDBL_MIN约为2×10 -308。 有超过2^32值的范围在完全,所以清楚地一个呼叫到rand()是不够的,以产生它们。 什么你需要做的就是产生你的双均匀的尾数,然后选择一个指数与指数分布,然后软糖事情位,以确保结果的范围。

如果您不需要在范围内的每个双是可能的,然后打开和关闭范围之间的差别是相当无关紧要的,因为在一个“真正的”连续均匀随机分布,发生的任何确切值的概率是0呢。 所以,你可能也仅仅产生在公开范围内的数字。

所有这一切说:是的,你提出的实现产生了在你说的范围值,并为封闭和半封闭的范围内,他们产生终点的概率为1/(RAND_MAX+1)左右。 这对于许多或最实际的目的不够好。

您与提供的+1和+2作品摆弄周围RAND_MAX+2是该范围内的double能只代表。 这是IEEE双精度和32位真int ,但它实际上不是由C标准保证。

(我忽略了你的使用long double ,因为它混淆了事情有点。它保证至少一样大double ,但也有共同的实现中,它是完全一样的double ,所以long不添加任何东西除了不确定性)。



Answer 2:

这个问题是没有准备好回答,因为这个问题已经完全确定。 特别是,不规范已经陈述了如何精细地设定,可以生成值的应该是分布式的。 为了说明,考虑[0,1]生成值,并且考虑与可表示的值的浮点格式:

0,1/16,2/16,3/16,4/16,6/16,8/16,12/16,1。

在这些值几个发行版可能会被认为是“统一”:

  • 选择每个概率相同。 这是均一的,离散值,但没有过的值之间的距离真正的统一密度。
  • 选择每个以一定的概率正比于在其附近的表示的值的密度。
  • 以相等的概率选择0,4/16,8/16,12/16,和1,保持在间隔相同的粒度。

我怀疑这些第一意,我会关闭它。 二是类似于由史蒂夫·杰索普的建议,但仍未完全确定。 应在0​​的概率正比于从它的中点的时间间隔到下一个点来选择? (这将给出的1/32的概率。)或者应该将其与集中在它的时间间隔相关联,从-1/32 1/32? (这将给出它的1/17的概率,假设1也分配的间隔延伸超出1/32本身。)

你可能有理由相信这是一个封闭的区间,所以应该在0和停止在1但是,假如我们有,对于一些应用,切碎通过分布[0,2]到区间[0,1]和(1, 2]。我们希望发行的工会在后两个间隔等于在原区间的分布。因此,我们应该分布很好地啮合。

第三种情况也有类似的问题。 也许,如果我们希望保留粒度这样,0应该有1/8的概率选择三个点1/4,1/2和3/4,每个概率1/4,和1的概率为1/8 。

除了指定的发电机所需的性质的这些问题,通过提问者提出的代码有一些问题:

  • 假定该RAND_MAX + 1是二的幂(并且因此通过将其分割为二进制浮点算术“好”),由RAND_MAX或RAND_MAX + 2分割可以导致生成的值有些不规则。 有可能是在他们奇怪quantizations。

  • 当1 /(RAND_MAX + 1)≤1/4 ULP(1),RAND_MAX /(RAND_MAX + 1)将上舍入并返回1,当它不应该因为间隔[0,1)。 (“ULP(1)”是指用于在所使用的浮点格式的值1至少精度的单位。)(这将不会已经结合长双测试中观察到,其中RAND_MAX有效数的比特内配合,但它会发生,例如,在RAND_MAX是2147483647和浮点类型是浮点型,其24位有效)。

  • 乘以(ba)和添加a介绍舍入误差,其后果的必须进行评估。 有许多情况下,诸如当ba小且a是大的,当ab跨乘零(从而导致近B还送虽然更精细的结果可表示粒度的损失),依此类推。

  • 下界的结果为(0,1)是最近的1 /(RAND_MAX + 2)的浮点值。 此结合的具有浮点值或期望的分布的细度没有关系; 那简直是兰德的实现产物。 在值(0,1 /(RAND_MAX + 2))而没有任何原因从问题规范所产生删去。 类似的伪影可以存在于上端(取决于特定的浮点格式,兰特实现和间隔的端点,B)。

我提交提问遇到没有答案的问题对于这种“简单”的问题的原因是,它不是一个简单的问题。



Answer 3:

首先,生成随机数[A,B]。 要生成随机数[A,B),只是产生一个随机数[A,B],检查它是否等于B,如果是的话再试一次。 同样,对于其他所有开区间变种。



Answer 4:

关闭我的头顶,我只是提供所有不同的浮点和整数类型(对于模板C ++实现加分)的变种,我会代替rand()有更好的东西( drand48()想到的)



Answer 5:

下面是我使用找到生成的数字基本错误(很粗)的测试。 它并不显示生成的数字是很好的,但他们不坏。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int main(int argc, char *argv[]) {

    long double x1,x2,x3,x4;
    if ( argc!=2 ) {
        printf("USAGE: %s [1,2,3,4]\n",argv[0]);
        exit(EXIT_SUCCESS);
    }

    srand((unsigned int)time(NULL));

    printf("This program simply generates random numbers in the chosen interval\n"
               "and looks for values on the boundary or outside it. When an\n"
               "allowable boundary is found, it reports it. Unexpected \"impossible\"\n"
               "values will be reported and the program will terminte. Under\n"
               "normal circumstances, the program should not terminate. Use ctrl-c.\n\n");

    switch ( atoi(argv[1]) ) {
        case 1:
            /* x1 will be an element of [0,1] */
            printf("NOTE: Testing [0,1].\n");
            while ( 1 ) {
                x1=((long double)rand()/RAND_MAX);
                if ( x1==0 ) {
                    printf("x1=0 ENCOUNTERED.\n");
                } else if ( x1==1 ) {
                    printf("x1=1 ENCOUNTERED.\n");
                } else if ( x1 < 0 ) {
                    printf("x1<0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x1 > 1 ) {
                    printf("x1>0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                }
            }
            break;
        case 2:
            /* x2 will be an element of [0,1) */
            printf("NOTE: Testing [0,1).\n");
            while ( 1 ) {
                x2=((long double)rand()/((long double)RAND_MAX+1));
                if ( x2==0 ) {
                    printf("x2=0 ENCOUNTERED.\n");
                } else if ( x2==1 ) {
                    printf("x2=1 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x2 < 0 ) {
                    printf("x2<0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x2 > 1 ) {
                    printf("x2>0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                }
            }
            break;
        case 3:
            /* x3 will be an element of (0,1] */
            printf("NOTE: Testing (0,1].\n");
            while ( 1 ) {
                x3=(((long double)rand()+1)/((long double)RAND_MAX+1));
                if ( x3==1 ) {
                    printf("x3=1 ENCOUNTERED.\n");
                } else if ( x3==0 ) {
                    printf("x3=0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x3 < 0 ) {
                    printf("x3<0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x3 > 1 ) {
                    printf("x3>0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                }
            }
            break;
        case 4:
            /* x4 will be an element of (0,1) */
            printf("NOTE: Testing (0,1).\n");
            while ( 1 ) {
                x4=(((long double)rand()+1)/((long double)RAND_MAX+2));
                if ( x4==0 ) {
                    printf("x4=0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x4==1 ) {
                    printf("x4=1 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x4 < 0 ) {
                    printf("x4<0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                } else if ( x4 > 1 ) {
                    printf("x4>0 ENCOUNTERED. Abnormal termination.\n");
                    exit(EXIT_FAILURE);
                }
            }
            break;
        default:
            printf("ERROR: invalid argument. Enter 1, 2, 3, or 4 for [0,1], [0,1), (0,1], and (0,1), respectively.\n");
            exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}


文章来源: Use rand() to generate uniformly distributed floating point numbers on (a,b), [a,b), (a,b], and [a,b]
标签: c random