我正在接收一个大致连续的整数序列(来自数据库密钥),并且我想以确定性的方式将每个整数映射到0和1之间的一个双精度数,以便所有双精度数的结果集为(接近)均匀分布。理想情况下,即使只接收到少量整数,也应该如此。
映射必须是确定性的,因为对于每个整数(在多个不同的机器上),它可能会发生多次,并且每次映射都将产生相同的两倍。
例如函数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
到目前为止,我能想到的最好方法是:
double mapToDouble(final int i) {
final String s = new StringBuilder().append(i).append(".0").reverse().toString();
return new Double(s);
}
对于样本量相对较小的最高有效位大约均匀分布,但对于较低有效位可以偏斜。
答案 0 :(得分:2)
当然,您可以使用Linear Congruential Generator进行映射。基本上,具有满足Hull–Dobell定理的适当参数的LCG会将[0 ... 2 64 )范围内的任何整数唯一地映射到[0 ... 2 64 )范围,可以这么说。双打不是唯一的,它们在[0 ... 1)范围内不够。
Java伪代码(很抱歉,Java很久以前使用过,此处假设Java 8带有Long)
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;
}
您可以尝试使用Lehmer RNG和质数253-111映射到唯一双精度数,这几乎可以保证统一的53位尾数。但是,模数计算必须明确进行。