当前位置: 首页 > 知识库问答 >
问题:

如何在Java中生成与Numpy中相同的伪随机数(对于相同的种子)?

缑嘉玉
2023-03-14

当使用相同的种子(例如12345)时,是否有任何选项可以像Numpy random一样在Java中生成相同的随机数。

在Numpy中,我得到的代码低于输出:0.9296160928171479

from numpy.random import RandomState
rs = RandomState(12345)
rs.random()

在Java中,我从下面的代码中获得输出:0.3618031071604718

import java.util.Random;
Random random = new Random(12345);
System.out.println(random.nextDouble());

我在Java中比较了SciKit学习和我自己的库中的一些方法的输出。为了生成相同的输出,我需要像Numpy一样生成相同的随机值(SciKit学习使用Numpy随机值)。

共有1个答案

彭正谊
2023-03-14

传统的NumPy随机生成器使用Mersenne Twister(MT)算法生成随机位,并将其转换或解释为所需的类型,而Java使用一种更简单的算法,称为LCG。要使用Java获得相同的原始位集,需要使用Apache的Mersenne Twister for Java。MT生成无符号32位整数,然后可以将其转换为其他范围或分布。如果需要具有64位精度的数字,则实现会隐式调用随机数生成器两次并合并结果。

然而,NumPy和Java中的数字表示似乎不同,因此仅获得相同的随机位是不够的。

让我们在Java和python中都使用MT,并比较结果。首先,看看Java示例代码

import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.MersenneTwister;

class QuickStart {
    public static void main(String[] args) {
        RandomGenerator prng = new MersenneTwister(0);
        for (int i = 0; i < 3; ++i) {
            long num = prng.nextLong();
            System.out.println(Long.toString(num) + "\t" + Long.toBinaryString(num));
        }
        System.out.println();
        for (int i = 0; i < 3; ++i) {
            int num = prng.nextInt();
            System.out.println(Integer.toString(num) + "\t" + Integer.toBinaryString(num));
        }
        System.out.println();
        for (int i = 0; i < 3; ++i) {
            double num = prng.nextDouble();
            System.out.println(Double.toString(num) + "\t" + Long.toBinaryString(Double.doubleToRawLongBits(num)));
        }
    }
}

这将产生输出

-8322921849960486353    1000110001111111000010101010110010010111110001001010101000101111
-5253828890213626688    1011011100010110101001100111010111011000001000011100110011000000
-7327722439656189189    1001101001001110101100110100001111011011101000100101001011111011

-1954711869     10001011011111010111011011000011
-656048793      11011000111001010111110101100111
1819583497      1101100011101001010010000001001

0.6235637015982585      11111111100011111101000011101111011101001010101100101010001000
0.38438170310239794     11111111011000100110011011010110110111000000000101101101110000
0.2975346131886989      11111111010011000010101100111010011110010001001011001111000100

而python的例子是:

import numpy
import bitstring


numpy.random.seed(0)
for i in range(3):
    state = numpy.random.get_state()
    num = numpy.random.randint(0, 2**64, dtype=numpy.uint64)
    print(num, bin(num), sep="\t")
print()

for i in range(3):
    state = numpy.random.get_state()
    num = numpy.random.randint(0, 2**32, dtype=numpy.uint32)
    print(num, bin(num), sep="\t")
print()

for i in range(3):
    state = numpy.random.get_state()
    num = numpy.random.random()
    f1 = bitstring.BitArray(float=num, length=64)
    print(num, f1.bin, sep="\t")

它产生输出:

10123822223749065263    0b1000110001111111000010101010110010010111110001001010101000101111
13192915183495924928    0b1011011100010110101001100111010111011000001000011100110011000000
11119021634053362427    0b1001101001001110101100110100001111011011101000100101001011111011

2340255427      0b10001011011111010111011011000011
3638918503      0b11011000111001010111110101100111
1819583497      0b1101100011101001010010000001001

0.6235636967859723      0011111111100011111101000011101111011010100101010110010101000100
0.3843817072926998      0011111111011000100110011011010110111011100000000010110110111000
0.2975346065444723      0011111111010011000010101100111010010111001000100101100111100010

你可以看到原始数字是一样的。二进制值的打印格式略有不同:如果使用内置的bin(),python将使用0b,而bitstring将一些二进制值放在前面,即前导零。由于整数的有符号/无符号类型不同,表示的值完全不同,但对于双精度,表示的差异很小。通过看到这种模式,可以用Java或python编写二进制数的解释器,以模仿其他语言的行为。

如果使用Mersenne Twister的另一个实现,请注意初始状态是如何初始化的。我不知道NumPy的传统随机初始化是否有文档记录,但它似乎使用了维基百科编写的相同内容(如果提供了32位整数),这是Matsumoto等人2007年提出的方法的特例(查看等式30)。在其他语言中还可以使用其他初始化方法,即使在给定的语言中,不同的组也可能会提出不同的实现(MS VC和GCC或boost的C std Mersene Twister实现是不同的)。甚至NumPy的新接口也使用了一种涉及哈希函数的不同技术。

 类似资料:
  • 问题内容: 我正在尝试Java 7的 ThreadLocalRandom,并发现它在多个线程中生成完全相同的随机数。 这是我的代码,在其中创建5个线程,每个线程打印出5个随机数: 输出: 为什么对于每个线程和程序的每次执行都获得相同的随机数? 问题答案: 似乎有一个关于此问题的公开错误。看这里和这里

  • 我如何在同一机器架构+映像(x86_64 Linux)上,从给定的种子跨不同的二进制生成一个保证的随机数序列?

  • 问题内容: 下面的代码旨在生成间隔为[1,100]的五个伪随机数的列表。我为with设置了种子,它以unix时间返回系统时间。当我使用Microsoft Visual Studio 2013在Windows 7上编译并运行该程序时,它会按预期运行(请参阅下文)。但是,当我在Arch Linux中使用g ++编译器执行此操作时,它的行为就很奇怪。 在Linux中,每次将生成5个数字。每次执行后4个数

  • 在我的计算机上卸载并重新安装C编译器 在我的计算机上安装和使用其他C编译器 使用相同的编译器在他人的计算机上运行该程序? 用不同的编译器(可能还有不同的操作系统)在其他人的计算机上运行程序? 还是仅仅是所有C编译器使用相同的RNG算法,所以伪随机序列(从一开始)对每个人都是一样的问题?

  • 问题内容: 在java中如何生成随机数? 问题答案: 在Java 1.7或更高版本中,执行此操作的标准方法如下: 请参阅相关的JavaDoc。这种方法的优点是不需要显式初始化java.util.Random实例,如果使用不当,可能会引起混乱和错误。 但是,相反,没有办法明确设置种子,因此在有用的情况下(例如测试或保存游戏状态或类似情况),很难重现结果。在这种情况下,可以使用下面显示的Java 1.

  • 问题内容: 我如何获得两个数组之间的按行比较,从而得到按行的真/假数组? 给定数据: 结果步骤1: 最终结果: 那么我如何获得阵列呢 ? PS:在此示例中,数组和 进行了排序,如果在您的解决方案中数组进行了排序很重要,也请提供信息 问题答案: 这是向量化的解决方案: 请注意,将的每行与按元素进行比较。然后,我们使用+推断每个子数组是否有所有行: