Java 三维随机数空间的生成算法
我正在寻找一种算法,在三维(或更好的n维)大范围空间中生成伪随机数。当使用种子初始化时,生成器应该能够为同一种子重复生成相同的数字 但与编程语言中可用的大多数生成器不同,它不应该只返回序列中的下一个随机数,而是为特定坐标生成数字,而不管请求值的顺序是什么 应该认为空间的大小太大,无法在初始化时生成所有数字。在Java中,它可能看起来像这样:Java 三维随机数空间的生成算法,java,algorithm,math,random,Java,Algorithm,Math,Random,我正在寻找一种算法,在三维(或更好的n维)大范围空间中生成伪随机数。当使用种子初始化时,生成器应该能够为同一种子重复生成相同的数字 但与编程语言中可用的大多数生成器不同,它不应该只返回序列中的下一个随机数,而是为特定坐标生成数字,而不管请求值的顺序是什么 应该认为空间的大小太大,无法在初始化时生成所有数字。在Java中,它可能看起来像这样: Random3D gen = new Random3D(seed); int n1 = gen.getInt(3,0,6); int n2 = gen.ge
Random3D gen = new Random3D(seed);
int n1 = gen.getInt(3,0,6);
int n2 = gen.getInt(2,-3,1);
...
我该怎么做这样的事
我在Java中使用Java.util.Random编写了一些代码,但是结果的质量不是很好。我相信您可以通过使用输入数字作为用于计算传递到标准RNG的种子的值来解决问题;如果我没有看错你的问题,你希望从相同的输入中得到相同的“随机”数,这是这个解决方案所能提供的。如果你想为同一个合作伙伴获得相同的结果,当你指定种子时,你并不是在寻找一个真正的随机生成器 你想要一个快速可靠的算法吗?对于一个快速的,这是一个看。要找一个更强壮的,你可以看看 您可以使用n维坐标加上种子来生成伪随机数生成器。例如,您可以计算sha1或md5或坐标+种子的任何其他散列,并在PRNG中使用它
编辑:对于一个简单的解决方案,math.random可以接收48位的种子(小于md5输出),这对于您的问题来说可能有点小(您提到的高维,对吗?具有较大的坐标?)我实现了以下想法:在显式(非迭代)中使用伪随机数生成器表单,以及消息摘要,以从参数生成正确的索引 (您也可以从中获取此源。)
package de.fenging_game.paul.examples;
导入java.math.biginger;
导入java.security.MessageDigest;
导入java.security.NoSuchAlgorithmException;
导入java.util.Random;
/**
*一个伪随机数生成器,它不
*生成一系列数字,但每个数字由
*一些输入(与之前的数字无关)。
*
*这是基于
*,并与SHA-1消息摘要相结合,以获得
*右索引。
*
*
*受到这个问题的启发
*在
*堆栈溢出,以及来自woliveirajr的答案。
*/
公共类伪随机{
/**
*此类的实例表示一系列
*整数,包括两个端点。
*/
公共静态最终类范围{
公共int min;
公共整数最大值;
公共范围(最小整数、最大整数){
this.min=min;
this.max=max;
}
/**
*将(正)BigInteger剪裁到表示的范围
*通过这个物体。
*@返回一个介于最小值和最大值之间的整数。
*/
最终整数剪辑(BigInteger-bigVal){
大整数模=
BigInteger.valueOf(最大值+1L-最小值);
返回值(int)(min+bigVal.mod(模数).longValue());
}
}
/*M=p*q=
510458987753305598818664158496165644577818051165198667838943583049282929852810917684801057127 *
1776854827630587786961501611493551956300146782768206322414884019587349631246969724030273647
*/
/**
*由两个大素数组成的大数。
*/
私有静态最终大整数M=
新的BigInteger(“90701151669688414188903413782441269599449657”+
"82009133495922185615411523457607691918744187485"+
"10492533485214517262505932675573506751182663319"+
"285975046876611245165890299147416689632169");
/*λ(M)=lcm(p-1,q-1)*/
/**
*λ(M)的值,其中λ是卡迈克尔函数。
*这是前代产品的最低公倍数
*M。
*/
私有静态最终大整数lambdaM=
新的BigInteger(“535057583484442070944517069391220634799707248289”+
"10045667479610928077057617288038459593720911813"+
"73249762745139558184229125081884863164923576762"+
"05906844204771187443203120630003929150698");
/**
*数字2作为BigInteger,用于计算。
*/
私有静态final biginger 2=biginger.valueOf(2);
/**
*种子值的模平方。
*/
私有大整数s_0;
/**
*用于转换输入数据的MessageDigest
*我们的PRNG的索引。
*/
私人消息摘要md;
/**
*使用给定的种子创建新的伪随机实例。
*/
公共伪随机(大整数种子){
试一试{
this.md=MessageDigest.getInstance(“SHA-1”);
}
捕获(nosuchalgorithmex异常){
抛出新的运行时异常(ex);
}
初始化(种子);
}
/**
*创建一个新的伪随机实例,由给定的种子进行种子设定。
*/
公共伪随机(字节[]种子){
这个(新的BigInteger(1,种子));
}
/**
*创建一个新的伪随机实例,
*由当前系统时间设定种子。
*/
公共伪随机{
这是(BigInteger.valueOf(System.currentTimeMillis());
}
/**
*将初始种子转换为以下值:
*可由生成器使用。(这是完全确定的。)
*/
私有无效初始化(BigInteger提案){
//我们希望我们的种子足够大,所以s^2>M。
大整数s=提案;
而(s.bitLength()>2
package de.fencing_game.paul.examples;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
/**
* A pseudo random number generator, which does not
* produce a series of numbers, but each number determined by
* some input (and independent of earlier numbers).
*<p>
* This is based on the
* <a href="http://en.wikipedia.org/wiki/Blum_Blum_Shub">Blum Blum Shub
* algorithm</a>, combined with the SHA-1 message digest to get the
* right index.
*</p>
*<p>
* Inspired by the question
* <a href="https://stackoverflow.com/q/6586042/600500">Algorithm
* for generating a three dimensional random number space</a> on
* Stack Overflow, and the answer from woliveirajr.
*/
public class PseudoRandom {
/**
* An instance of this class represents a range of
* integer numbers, both endpoints inclusive.
*/
public static final class Range {
public int min;
public int max;
public Range(int min, int max) {
this.min = min;
this.max = max;
}
/**
* clips a (positive) BigInteger to the range represented
* by this object.
* @returns an integer between min and max, inclusive.
*/
final int clip(BigInteger bigVal) {
BigInteger modulus =
BigInteger.valueOf(max + 1L - min);
return (int)(min + bigVal.mod(modulus).longValue());
}
}
/* M = p * q =
510458987753305598818664158496165644577818051165198667838943583049282929852810917684801057127 *
1776854827630587786961501611493551956300146782768206322414884019587349631246969724030273647
*/
/**
* A big number, composed of two large primes.
*/
private static final BigInteger M =
new BigInteger("90701151669688414188903413878244126959941449657"+
"82009133495922185615411523457607691918744187485"+
"10492533485214517262505932675573506751182663319"+
"285975046876611245165890299147416689632169");
/* λ(M) = lcm(p-1, q-1) */
/**
* The value of λ(M), where λ is the Carmichael function.
* This is the lowest common multiple of the predecessors of
* the two factors of M.
*/
private static final BigInteger lambdaM =
new BigInteger("53505758348442070944517069391220634799707248289"+
"10045667479610928077057617288038459593720911813"+
"73249762745139558184229125081884863164923576762"+
"05906844204771187443203120630003929150698");
/**
* The number 2 as a BigInteger, for use in the calculations.
*/
private static final BigInteger TWO = BigInteger.valueOf(2);
/**
* the modular square of the seed value.
*/
private BigInteger s_0;
/**
* The MessageDigest used to convert input data
* to an index for our PRNG.
*/
private MessageDigest md;
/**
* Creates a new PseudoRandom instance, using the given seed.
*/
public PseudoRandom(BigInteger seed) {
try {
this.md = MessageDigest.getInstance("SHA-1");
}
catch(NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
initializeSeed(seed);
}
/**
* Creates a new PseudoRandom instance, seeded by the given seed.
*/
public PseudoRandom(byte[] seed) {
this(new BigInteger(1, seed));
}
/**
* Creates a new PseudoRandom instance,
* seeded by the current system time.
*/
public PseudoRandom() {
this(BigInteger.valueOf(System.currentTimeMillis()));
}
/**
* Transforms the initial seed into some value that is
* usable by the generator. (This is completely deterministic.)
*/
private void initializeSeed(BigInteger proposal) {
// we want our seed be big enough so s^2 > M.
BigInteger s = proposal;
while(s.bitLength() <= M.bitLength()/2) {
s = s.shiftLeft(10);
}
// we want gcd(s, M) = 1
while(!M.gcd(s).equals(BigInteger.ONE)) {
s = s.add(BigInteger.ONE);
}
// we save s_0 = s^2 mod M
this.s_0 = s.multiply(s).mod(M);
}
/**
* calculates {@code x_k = r.clip( s_k )}.
*/
private int calculate(Range r, BigInteger k) {
BigInteger exp = TWO.modPow(k, lambdaM);
BigInteger s_k = s_0.modPow(exp, M);
return r.clip(s_k);
}
/**
* returns a number given by a range, determined by the given input.
*/
public int getNumber(Range r, byte[] input) {
byte[] dig;
synchronized(md) {
md.reset();
md.update(input);
dig = md.digest();
}
return calculate(r, new BigInteger(1, dig));
}
/**
* returns a number given by a range, determined by the given input.
*/
public int getNumber(Range r, int... input) {
byte[] dig;
synchronized(md) {
md.reset();
for(int i : input) {
md.update(new byte[]{ (byte)(i >> 24), (byte)(i >> 16),
(byte)(i >> 8), (byte)(i >> 0)} );
}
dig = md.digest();
}
return calculate(r, new BigInteger(1, dig));
}
/**
* Test method.
*/
public static void main(String[] test) {
PseudoRandom pr = new PseudoRandom("Hallo Welt".getBytes());
Range r = new Range(10, 30);
for(int i = 0; i < 10; i++) {
System.out.println("x("+i+") = " + pr.getNumber(r, i));
}
for(int i = 0; i < 5; i++) {
for(int j = 0; j < 5; j++) {
System.out.println("x("+i+", "+j+") = " +
pr.getNumber(r, i, j));
}
}
// to show that it really is deterministic:
for(int i = 0; i < 10; i++) {
System.out.println("x("+i+") = " + pr.getNumber(r, i));
}
}
}