【问题标题】:Migrating C# to Python - Random class将 C# 迁移到 Python - 随机类
【发布时间】:2012-04-04 06:54:31
【问题描述】:

我需要将一些 C# 代码迁移到 Python。原始代码使用Random 类。迁移的代码必须是循环准确的(即连续调用Next() 必须在两个代码中产生相同的结果)。一些问题:

  • 在 Python 中是否有与 C# 的 Random 等效的调用?
  • 头韵,假设我可以修改这两个源,是否有一个伪随机库同时适用于 C# 和 Python?

【问题讨论】:

  • 为两种语言编写自己的 PRNG。

标签: c# python random


【解决方案1】:

我知道这是一个老问题,但我最终需要一个解决方案。我最终在 python 中实现了 C# 的 Random 类。只要您不需要大于 2147483647 的随机数,它就可以工作,我最终不需要该功能,所以我没有实现它。

https://gist.github.com/BadStreff/541cf2e6953b3c666f83127a1d4f6a47

from ctypes import *
# implemented from:
# http://referencesource.microsoft.com/#mscorlib/system/random.cs,dec894a7e816e665
class Random(object):
    def __init__(self, seed):
        self.seed = c_int(seed).value
        self.MBIG = 2147483647
        self.MMIN = -2147483648
        self.MZ = 0
        self.MSEED = 161803398
        self.SeedArray = [0] * 56

        if seed == self.MMIN:
            subtraction = self.MBIG
        else:
            subtraction = abs(seed)

        mj = c_int(self.MSEED - subtraction).value
        self.SeedArray[55] = mj
        mk = 1
        for i in range(1, 55):
            ii = (21 * i) % 55
            self.SeedArray[ii] = mk
            mk = mj - mk
            if mk < 0:
                mk += self.MBIG
            mj = self.SeedArray[ii]
        for k in range(1, 5):
            for i in range(1, 56):
                self.SeedArray[i] -= self.SeedArray[1 + (i + 30) % 55]
                if self.SeedArray[i] < 0:
                    self.SeedArray[i] = c_int(self.SeedArray[i] + self.MBIG).value
        self.inext = 0
        self.inextp = 21
        self.seed = 1

    def InternalSample(self):
        locINext = self.inext + 1
        locINextp = self.inextp + 1

        if locINext >= 56:
            locINext = 1
        if locINextp >= 56:
            locINextp = 1

        retVal = c_int(self.SeedArray[locINext] - self.SeedArray[locINextp]).value
        if retVal == self.MBIG:
            retVal -= 1
        if retVal < 0:
            retVal = c_int(retVal + self.MBIG).value
        self.SeedArray[locINext] = retVal
        self.inext = locINext
        self.inextp = locINextp
        return retVal

    def Next(self, minValue=None, maxValue=None):
        if minValue == None:
            return self.InternalSample()
        valRange = maxValue - minValue
        if valRange <= self.MBIG:
            return int(c_float(self.Sample() * valRange).value) + minValue
        else:
            return self.GetSampleForLargeRange() * valRange + minValue

    def GetSampleRangeForLargeRange(self):
        pass

    def Sample(self):
        s = self.InternalSample()
        ret = c_double(s * c_double(1.0/self.MBIG).value).value
        # print(f'sample: {s}\nret: {ret}')
        return ret

【讨论】:

  • 在这里发布你的实现,以防要点被删除或链接失效。
【解决方案2】:

我不知道有任何库可以同时用于 Python 和 C# 并为两者生成相同的随机数。但是,您也许可以利用 IronPython。 IronPython 和 CPython 的默认 Random 实现不同,但 WichmannHill 类没有。

您可以使用 C# 在 IronPython 中实例化 WichmannHill 类,并为相同的种子获得与 CPython 相同的值。或者,您可以通过翻译random.py 中的 Python 代码,相对轻松地在 C# 中实现 Wichmann-Hill 算法。

另一种选择是采用 Random 的 Mersenne Twister 算法的 CPython implementation 并将其转换为 C# 以获得相同的结果。

【讨论】:

  • 我赞成使用 Mersenne Twister。它比内置的 Random() 更好的随机化器(至少对于 c#,我不了解 IronPython)。不过不要将它(或者实际上是 Random())用于加密。
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-11
  • 2020-05-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多