Java Apache Math3 MersenneTwister VS Python随机

时间:2014-08-04 20:29:26

标签: java python scala random mersenne-twister

我的任务是将一些python代码移植到Scala用于研究目的。 现在我使用了Apache Math3公共库,并且遇到了MersenneTwister的问题。

在Python中:

SEED = 1234567890

PRIMARY_RNG = random.Random()
PRIMARY_RNG.seed(SEED)
n = PRIMARY_RNG.randrange((2**31) - 1) #1977150888

在Scala中:

val Seed = 1234567890
val PrimaryRNG = new MersenneTwister(Seed)
val n = PrimaryRNG.nextInt(Int.MaxValue) //1328851649

我在这里缺少什么?两者都是MersenneTwister, 和Int.MaxValue = 2147483647 = (2**31) - 1

3 个答案:

答案 0 :(得分:2)

Apache Commons Math显然是uses an integer as the base source of randomness,虽然我不太确定它是如何提取它的,而Python uses the double generated by a C version of the algorithm

种子值的处理方式也可能存在差异,但由于它们甚至没有以相同的方式读出这些位,即使底层的伪随机生成器是相同的,人们也不会期望它们具有可比性。

答案 1 :(得分:2)

正如我已经在评论中发布的那样,获取下一个整数的主要算法在Python和Apache Math之间是相同的(源代码hereherehere)。跟踪代码似乎主要区别在于两个版本如何为生成器播种。 Python版本将给定的种子转换为数组并从数组中播种,而Apache Math版本具有单独的算法,用于从单个数字播种。因此,为了使Apache Math nextInt(...)方法以Python randrange(...)方法的保存方式运行,您应该使用数组为Apache Math版本提供种子。

(我不知道Scala所以下面的代码是用Java编写的)

MersenneTwister rng = new MersenneTwister();
rng.setSeed(new int[] {1234567890});
System.out.println(rng.nextInt(Integer.MAX_VALUE)); // 1977150888

另请注意,random()nextDouble()等所有其他方法完全不同,因此此播种机制可能只会使nextInt(...)randrange(...)成为返回相同的结果。

答案 2 :(得分:0)

万一有人需要这样做,我想出了一个基于CPython implementation here的工作版本。

注意:如果使用字符串作为种子,random.seed()在Python 2和3之间进行了更改。此处的pythonStringHash函数与Python 2版本兼容,或者在Python 3中与random.seed(s, version=1)兼容。

private static long pythonStringHash(String s) {
  char[] chars = s.toCharArray();
  long x;
  if (s.isEmpty()) {
    x = 0;
  } else {
    x = chars[0] << 7;
  }

  for (char c : chars) {
    x = ((1000003 * x) ^ c);
  }

  x ^= chars.length;
  if (x == -1) {
    return -2;
  }
  return x;
}

private static void pythonSeed(MersenneTwister random, long seed) {
  int[] intArray;
  if (Long.numberOfLeadingZeros(seed) >= 32) {
    intArray = new int[] { (int) seed };
  } else {
    intArray = new int[] { (int) seed, (int) (seed >> 32) };
  }
  random.setSeed(intArray);
}

public static RandomGenerator pythonSeededRandom(String seed) {
  MersenneTwister random = new MersenneTwister();
  pythonSeed(random, pythonStringHash(seed));
  return random;
}

从那里开始,pythonSeededRandom("foo").nextDouble()等于random.seed("foo"); random.random()