Java 从随机长序列生成随机双精度

Java 从随机长序列生成随机双精度,java,random,underflow,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 是这样吗?是否存在任何数值问题(底流?) 可以更好/更快吗 谢谢。不完全是。我认为更简单的方法是做到以下几点: newrandom(seed).nextDouble()我希望

在Java中,我有一个随机生成器,它生成从-2^63到2^63的随机数,而不是Java.util.random

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

return (seed/(double)(9223372036854775807L))/2+0.5;//seed is a random long
是这样吗?是否存在任何数值问题(底流?)

可以更好/更快吗


谢谢。

不完全是。我认为更简单的方法是做到以下几点:
newrandom(seed).nextDouble()

我希望只看到一个分区

0.5+(seed/1.84467440737096E+19);

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

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

我将使用最有效的方法,并确保不会因为舍入或表示错误而出现有趣的行为

double d = Math.scalb(seed >>> 1, -63);
一个double只能使用53位,因此一些位将被丢弃

如果你跑

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

0.5
种子为0时,得到0.0


如果种子值为-1,则得到1.0,最快的方法可能是将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;
对于(inti=52;(种子>>>i&1)>0;i++)指数++;

double x=double.longBitsToDouble(seed&0x000fffffffffffl |)((1022-指数)你可以去掉
/2
并将其折叠到
seed/xxx
部分不,那太好了,不能太长。我怎么会那么笨?谢谢。@FabioF。但你没有说过你不能。;)我需要一个大的周期,通常生成器用于random long,但我也应该实现double random;返回d+0.5;我得到这些数字:7.60172909551165E27 | 2.60628963406992396E35 | 4.0765687952289006E36这个种子-7545188140698174557我得到这个数字1.1819490194320679(大于1)。现在已经很晚了。;)我怀疑63是否正确。你现在可以试试吗?嗯,我已经删除了评论。。现在的数字在随机范围内。。但是它们非常接近于零。。我应该再做些测试!:)@法比奥夫。啊,这平均随机地分布了0到1之间所有可能的双打,但是因为有更多可能的小双打,所以在这个意义上它的分布是不均匀的。哇,这太棒了,太糟糕了。。无论如何,我得到的数字大于1(1.3484676232953214,长9223048428104072362)。