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