Migrating C# to Python - Random class

Go To StackoverFlow.com

3

I need to migrate some C# code to Python. The original code makes use of the Random class. The migrated code must be cycle-accurate (namely consecutive calls to Next() must produce the same results in both codes). Some questions:

  • Is there a call-equivalent to C#'s Random in Python?
  • Alliteratively, assuming I can modify both sources, is there a pseudo-random library which works with both C# and Python?
2012-04-04 06:54
by bavaza
Write your own PRNG for both languages - David Heffernan 2012-04-04 07:49


1

I don't know of any library that is available for both Python and C# and which generates the same random numbers for both. However, you may be able to take advantage of IronPython. The default Random implementation differs between IronPython and CPython, but the WichmannHill class does not.

You can use C# to instantiate the WichmannHill class in IronPython and get the same values as CPython for the same seed. Alternatively, you can implement the Wichmann-Hill algorithm in C# relatively easily by translating the Python code in random.py.

Another option is to take the CPython implementation of Random's Mersenne Twister algorithm and translate that to C# to get identical results.

2012-04-04 07:37
by Gabe
I second the use of Mersenne Twister. It's a much better randomiser than the built-in Random() (for c# at least, I don't know about IronPython). Don't use it (or indeed Random()) for cryptography though - Matthew Watson 2012-04-04 08:05


1

I know this is an old question, but I ended up needing a solution to this. I ended up implementing C#'s Random class in python. It works as long as you don't need random numbers larger than 2147483647, I ended up not needing that functionality so I left it unimplemented.

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
2017-04-16 22:49
by BadStreff
Post your implementation here, in case the gist gets deleted or the link goes down - Adam 2017-04-16 23:16
Ads