Java 如何确定地将序列整数映射到均匀分布的双精度

Java 如何确定地将序列整数映射到均匀分布的双精度,java,random,hash,Java,Random,Hash,我正在接收一个大致连续的整数序列(来自数据库键),我希望以确定的方式将每个整数映射到0和1之间的一个double,以便所有double的结果集(接近)均匀分布。理想情况下,即使只接收到少量整数,也应如此 映射需要是确定性的,因为每个整数(在多个不同的机器上)可能会发生多次,并且每次映射时产生的double应该是相同的 e、 g.下面的函数mapToDouble应该是什么样子 final int start = 100000; final int size = 2000; final double

我正在接收一个大致连续的整数序列(来自数据库键),我希望以确定的方式将每个整数映射到0和1之间的一个double,以便所有double的结果集(接近)均匀分布。理想情况下,即使只接收到少量整数,也应如此

映射需要是确定性的,因为每个整数(在多个不同的机器上)可能会发生多次,并且每次映射时产生的double应该是相同的

e、 g.下面的函数mapToDouble应该是什么样子

final int start = 100000;
final int size = 2000;
final double[] results = new double[size];

for (int i = 0; i < size; i++) {
    results[i] = mapToDouble(i + start)
}

// results is uniformly distributed
对于样本量相对较小的最高有效位,它近似均匀分布,但对于较低有效位,它可能会倾斜。

当然,您可以使用它来进行映射。基本上,具有满足赫尔-多贝尔定理的适当参数的LCG将[0…264)范围内的任何整数唯一地映射到[0…264)范围内的另一个整数,可以说是良好的位切碎器。双精度不会是唯一的,在[0…1)范围内不够

Java伪代码(对不起,Java很久以前就有了,这里假设有Java8)

您可以尝试使用带素数的函数来映射到唯一的double,这几乎保证了53位尾数的一致性。但是,必须显式地进行模计算。

当然,您可以使用该函数来进行映射。基本上,具有满足赫尔-多贝尔定理的适当参数的LCG可以唯一映射[0…264)范围转换为[0…264)范围内的另一个范围,可以说是良好的位切碎器。双精度不会是唯一的,在[0…1)范围内不够

Java伪代码(对不起,Java很久以前就有了,这里假设有Java8)


您可以尝试使用带素数的函数映射到唯一的double,这几乎保证了53位尾数的一致性。但是,必须显式地进行模计算。

当前的方法没有那么大帮助。“0.2”嗯,如果您知道整数的范围,请参阅,例如
[0,x]
其中
x
是您期望的最大值,为什么不干脆
i/(double)x
(只有当
x
不是双精度时才需要强制转换)?每个
int
值(从
整数.MIN\u值
整数.MAX\u值
)必须生成唯一的
double
值吗?@Thomas问题是我没有该范围内的所有值,只是从该范围内的某个值开始的序列。@DodgyCodeException不,它不必是唯一的当前方法没有多大帮助。“0.2”嗯,如果您知道整数的范围,请参见,例如
[0,x]
其中
x
是您期望的最大值,为什么不干脆
i/(double)x
(只有当
x
不是双精度时才需要强制转换)?每个
int
值(从
整数.MIN\u值
整数.MAX\u值
)必须生成唯一的
double
值吗?@Thomas问题是我没有该范围内的所有值,只是从该范围内的某个值开始的序列。@DodgyCodeException不,它不必是唯一的
double mapToDouble(final int i) {
        final String s = new StringBuilder().append(i).append(".0").reverse().toString();
        return new Double(s);
    }
static final long a = Long.parseUnsignedLong("2862933555777941757"); // values taken from https://nuclear.llnl.gov/CNP/rng/rngman/node4.html
static final long c = Long.parseUnsignedLong("3037000493");

double mapToDouble(final int i) {
    long seed = (long)i;
    long mapl = a * seed + c; // should do wraparound automatically, or use Long.remainderUnsigned
    double x  = (x >>> 11) * 0x1.0p-53; // see http://xoshiro.di.unimi.it/
    return x;
}