Java7随机类

Java7随机类,java,Java,为什么java中的generator.nextDouble()只返回0到1之间的值?generator.nextInt()方法要求输入限制值。为什么使用Double方法不是这样?您可以简单地使用这个习惯用法来实现您想要做的事情: double max = 100000; // just an example double randomDouble = (new Random()).nextDouble() * max; 理论上,我认为没有充分的理由说明他们不能提供 下面是这样一种方法。我认为这

为什么java中的
generator.nextDouble()
只返回0到1之间的值?
generator.nextInt()
方法要求输入限制值。为什么使用
Double
方法不是这样?

您可以简单地使用这个习惯用法来实现您想要做的事情:

double max = 100000; // just an example
double randomDouble = (new Random()).nextDouble() * max;
理论上,我认为没有充分的理由说明他们不能提供 下面是这样一种方法。我认为这不是因为 上面的成语很简单,没有人抱怨:-)


我想问一下API设计的动机。这有点推测性,但选择这种设计至少有一个很好的理由,那就是它易于正确实现,同时仍然可以提供任意大小的随机数(因为您可以缩放结果)

另一个原因可能是
nextDouble()
的结果范围遵循浮点PRNG的长期惯例


我很感激您发现整数和浮点API之间的差异令人不安,但这绝不是Java(和其他)整数和FP API之间的唯一区别。这两种数字表示的用途完全不同,很少相交。强迫他们使用类似的API没有什么好处。

这个答案有点推测性,但我想原因是随机数生成器应该统一返回pseadorandoom double。均匀地生成二重数一点也不简单,因为二重数本身并不是均匀分布的

忽略符号,双精度或浮点数通常以
m*2^e
的形式存储,其中
m
e
具有固定的位宽度,其中
m
被解释为介于
0
(包含)和
1
(排除)之间的数字。这意味着对于高数字,两个连续双打之间的差异要比小数字大得多。因此,简单地用随机位填充一个double不会产生均匀分布的伪随机数

相反,解决方案是将指数
e
固定为0,并仅选择随机尾数
m
,这将产生一个均匀分布的介于0和1之间的双精度。如果需要不同范围内的随机双精度,可以将数字与所需范围相乘:

double randomDouble = rng.nextDouble() * range;

如果范围不太大,这在实践中就足够了。

从概念的角度来看,可以认为0.0和1.0之间的间隔在数学意义上是很好的:给定一个介于0.0和1.0之间的随机数,在任意范围内计算一个随机数是很简单的。当然,可以在
Random
类中插入实用程序方法,实现同样简单:

public double nextDouble(double min, double max) {
    return min + nextDouble() * (max - min);
}
现在有人可能会问,为什么这样一种方法不是最基本的实现。也就是说,为什么应该基于现有的
nextDouble()
方法来实现此方法,以及为什么没有“直接”生成所需范围内的值的方法

已经指出了一个重要的点:原因可能是0.0和1.0之间的范围更适合表示均匀分布的值

当查看(或者更确切地说:仔细阅读)有关的详细信息时,您将看到值的密度随着值的增大而减小

当您启动并输入0.0、1.0和1.70141*10^38的值时,您将看到它们的表示形式(此处为
float
——该语句类似地适用于
double
):

所以实际上,0.0到1.0之间的浮点数与1.0到170141163178059628000168797686300000000.0之间的浮点数基本相同。实现一个好的、统一的随机数生成器并非易事,考虑到可表示值本身并非均匀分布的问题,为任意范围创建一个专用实现几乎是不可能的


因此,对于0.0到1.0的范围,我们可以做出一个坚实的陈述,即值是均匀分布的。对于其他范围,人们可能会争论“一致性”对于某个范围实际上意味着什么…

如果你想要一个介于0.00和10.000之间的双精度,你可以简单地按范围进行缩放,执行
10.00*generatorNextDouble()
Random.nextDouble()返回一个介于0和1之间的随机双精度值。要放大它,请将该值乘以您希望的范围。因为这就是它的设计行为:@Abdulgood89,
Random.nextDouble()
被记录为返回0.0-1.0范围内均匀分布的伪随机值,如OP所说。如果它对你有不同的影响,那么你应该把你的虚拟机寄回去要求退款。@JohnBollinger-Haaa!请退票一张!这是一个很好的观察。但是,我想问一下,统一分配的定义是什么?如果
m
只有两位且
e
为0,则只有四个可能的双精度值:0、1.0、2.0和3.0,每个值的概率为0.25,而(0、4.0)中的所有其他双精度值(如1.5和2.5)的返回概率为零。现在,如果实现只是放大该值(就像您的代码片段所做的那样),那么返回四个双精度值的概率是0.25,其余的概率都是零。这被认为是“不均匀”?@leeyuiwah是的,如果你乘以一个范围,那么结果将不再均匀。这就是为什么我写道它“在实践中足够好”,从而暗示它实际上在理论上根本不好;-)。这就是我认为Java没有提供一个库方法来为您进行缩放的原因:它不再是统一的。应用程序编写者可能会认为这在他们的应用程序中并不重要,但这个决定应该
public double nextDouble(double min, double max) {
    return min + nextDouble() * (max - min);
}
0.0          =  0x00000000 = 0
1.0          =  0x3F800000 = 1065353216
1.7...*10^38 =  0x7EFFFFFE = 2130706430