从随机长​​度生成随机双精度

时间:2012-05-07 19:59:09

标签: java random underflow

Java中的

我有一个随机生成器,它生成从-2 ^ 63到2 ^ 63的随机数,而不是java.util.Random。

我需要在(0,1)中生成随机双精度,这是我到目前为止所做的:

return (seed/(double)(9223372036854775807L))/2+0.5;//seed is a random long

这是对的吗?有没有数值问题(下溢?)?

可能更好/更快?

谢谢。

5 个答案:

答案 0 :(得分:1)

我更愿意只看到一个部门。

0.5+(seed/1.84467440737096E+19);

那就是说,你将遇到浮点精度问题,因为你有64个随机整数位,然后尝试将其压缩到53位双精度。你可能最好为浮点值制作一个专用的生成器,但我不能肯定地说,因为我不知道你的动机。

答案 1 :(得分:1)

我会使用Math.scalb作为最有效的,并确保由于舍入或表示错误而没有有趣的行为

double d = Math.scalb(seed >>> 1, -63);

你只能在一个双精度中使用53位,所以有些会被丢弃。

如果你跑

long seed = Long.MAX_VALUE;
System.out.println(Math.scalb(seed >>> 1, -63));

打印

0.5

如果种子为0,则得到0.0

种子为-1,你得到1.0

答案 2 :(得分:1)

最快的方法可能就是将long中的前三位设置为0,然后使用这些位进行加倍。:

double rand = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);

这可以通过强制符号为正,指数小于0来实现,这将导致尾数至少向右移动一次。假设长的所有整数都是完全随机的,它给出了均匀分布。这是一个完整的Java程序,它使用Random生成随机long,然后这个方法将它们转换为0到1之间的double:

import java.util.Random;

class Main{
    public static void main(String[] args){
        Random rand = new Random();
        long seed = rand.nextLong();
        double x = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
        System.out.println(x);
    }
}

这是10次执行的输出:

1.1211565592484309E-247
8.84224349357039E-242
6.956043405745214E-271
3.747746366809532E-232
9.302628573486166E-158
1.1440116527034282E-166
1.2574577719255876E-198
5.104999671234867E-269
3.360619724894072E-213
1.5654452507283312E-220

修改

这使得所有可能的双精度在0和1之间均匀分布。由于还有更多的小双打,你可能永远不会看到接近1的数字。你可以通过根据数字的位生成一个新的指数来解决这个问题。现有的,但你需要一个循环来做它,所以它可能不是考虑到这个因素后最快的方法:

long exponent = 0;
for(int i = 52; (seed >>> i & 1) > 0; i++) exponent++;
double x = Double.longBitsToDouble(seed & 0x000FFFFFFFFFFFFFL | ((1022 - exponent) << 52));
  

0.4773960377161338
      0.929045618651037
      0.7183096209363845
      0.33962049395497845
      0.45568660174922454
      0.11670190555677815
      0.09371618427480996
      0.8192870898479095
      0.9365016017283178
      0.11311614413193898

答案 3 :(得分:0)

不完全是。我认为更简单的方法是执行以下操作: new Random(seed).nextDouble()

答案 4 :(得分:0)

除非我误读你需要从0到1的随机双精度,否则Java内置的Math.random就是这样。因此,您可以避免目前正在进行的所有转换。