2012-04-04 38 views
3

我需要一些C#代碼移植到Python。原始代碼使用Random類。遷移代碼必須是週期準確的(即連續調用Next()必須產生在兩個碼相同的結果)。一些問題:遷移C#到Python - Random類

  • Python中是否存在與C#的Random相當的調用?
  • Alliteratively,假設我可以修改這兩個來源,有沒有與C#和Python的作品僞隨機庫?
+0

寫自己的PRNG兩種語言。 – 2012-04-04 07:49:34

回答

1

我不知道任何可用於Python和C#的庫,它們都爲這兩個庫生成相同的隨機數。但是,您可能能夠利用IronPython。默認Random實現IronPython和CPython中之間是不同的,但WichmannHill類沒有。

您可以使用C#來實例化的IronPython的WichmannHill類並獲得儘可能CPython中相同的值相同的種子。或者,您可以通過翻譯random.py中的Python代碼,相對容易地在C#中實現Wichmann-Hill算法。

另一種選擇是採取Random的Mersenne Twister算法的CPython implementation,並將其轉換爲C#以獲得相同的結果。

+0

我第二次使用Mersenne Twister。這是一個比內置Random()更好的randomiser(至少對於c#而言,我不知道IronPython)。儘管如此,不要使用它(或者確實是Random())來進行加密。 – 2012-04-04 08:05:40

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 
+0

在此處發佈您的實施,以防止要點被刪除或鏈接關閉。 – Adam 2017-04-16 23:16:01