【发布时间】:2012-09-07 18:03:33
【问题描述】:
我想在一个地方收集在所有四种类型的间隔上生成随机数的“最佳”方式。我厌倦了谷歌搜索。搜索结果出现了很多废话。甚至相关的结果也是页面或博客,这些页面或博客通常是完全错误的,或者在讨论中自封的专家在某些技术上存在分歧,通常他们的“答案”似乎暴露了他们不了解不同的类型(关闭、开、半开)的区间。对于这样一个“简单”的问题,我厌倦了阅读有关在 C 中生成随机数的不良信息。
请告诉我如何生成均匀分布的浮点数。这是我在 (a,b)、[a,b)、(a,b] 和 [a,b] 上的典型方式(以“long double”为例):
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() 的返回值进行强制转换是必要的,不仅因为我们想避免整数除法,而且因为它们是整数,否则加一(或二)可能会使它们溢出。
我认为“double”和“float”的版本完全相同,只是替换了类型。不同的浮点类型有什么微妙之处吗?
您发现上述实现有什么问题吗?如果是这样,您将如何解决?
编辑:上述实现通过了必要的测试以使其正确(至少在运行 64 位 Linux 的 64 位 Intel Core 2 Duo 机器上):x1 可以生成 0 和 1,x2 可以生成 0 但没有'未见生成 1,x3 可生成 1 但未见生成 0,x4 未见生成 0 或 1。
【问题讨论】:
-
您描述的测试不足以测试正确性。它们仅测试边界违规,并且仅针对浮点格式和一兰特实现间隔的特定情况。适当的测试还需要解决分布是否满足所需的均匀性标准以及其他格式是否可能发生绑定违规。您的问题没有指定您想要什么分布:浮点格式更精细,结果应该更精细,还是应该在整个间隔内保持粒度?
-
我使用了“必要”这个词的技术含义。我同意你的观点,测试是不够的。
-
我建议您将以下内容添加到问题规范中:在为区间 [a 生成值时,结果应该恰好是 a 的概率是多少, b) 和 [a, b]? b 也是如此? (我假设 a 和 b 始终可以以目标格式表示。如果不是,则必须解决其他问题。)在 ( a, b),尤其是在浮点格式的精细度发生变化的子区间中。一旦问题得到充分说明,就可以设计解决方案。