【问题标题】:Java Apache Math3 MersenneTwister VS Python randomJava Apache Math3 MersenneTwister VS Python 随机
【发布时间】:2014-09-27 10:03:35
【问题描述】:

我的任务是将一些 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

【问题讨论】:

  • 真的很好奇 - 为什么 MersenneTwister 比 Java util 生成的 UUID 更好?
  • 好问题 - 在 python 源代码中,他们说它是最好的,老实说,虽然它超出了问题的范围,因为我正在复制结果。但我也很好奇
  • 您是否也尝试过 colt 只是为了了解这些实现之间的区别?另外,既然它是一个随机数生成器(除非我误解了),为什么值不能不同?
  • 因为它是一个伪随机数生成器,所以如果你给它一个种子,第一次调用总是会产生相同的数字。此外,我将 Apache Math3 用于许多其他功能,包括 2 个数学库有点浪费,afaik Math3 也非常全面。
  • 查看python使用的C代码here和Apache数学代码here似乎MersenneTwister.next(bits)的Python等价物是generate_int32(...)方法,两者看起来几乎相同但是其余的实现有些不同。

标签: java python scala random mersenne-twister


【解决方案1】:

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

种子值的处理方式也可能有所不同,但由于它们甚至不会以相同的方式读取位,因此即使底层伪随机生成器相同,也不会期望它们具有可比性.

【讨论】:

  • 嗯,这是一个非常令人失望的简单答案。只是让问题悬而未决。
  • (不是你的意思,因为我希望我是个白痴)
【解决方案2】:

正如我已经在 cmets 中发布的那样,获取下一个整数的主要算法在 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(...) 返回相同的结果。

【讨论】:

    【解决方案3】:

    如果有人需要这样做,我想出了一个基于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()

    【讨论】:

      猜你喜欢
      • 2017-04-11
      • 1970-01-01
      • 2014-10-23
      • 2015-05-08
      • 1970-01-01
      • 2012-11-23
      • 2018-08-27
      • 1970-01-01
      • 2015-09-29
      相关资源
      最近更新 更多