Skip to content

Instantly share code, notes, and snippets.

@aoirint
Last active June 6, 2026 02:02
Show Gist options
  • Select an option

  • Save aoirint/759a46aa283a40bf3bdf8b1153d8858a to your computer and use it in GitHub Desktop.

Select an option

Save aoirint/759a46aa283a40bf3bdf8b1153d8858a to your computer and use it in GitHub Desktop.
"""
# Mono System.Random Compatibility Implementation
This implementation targets compatibility with the historical
System.Random implementation used by Mono-based runtimes.
## Implementation Reference
This implementation is a Python port of the .NET Framework 4.6.2
Reference Source implementation of System.Random.
Reference:
https://github.com/microsoft/referencesource/blob/4fe4349175f4c5091d972a7e56ea12012f1e7170/mscorlib/system/random.cs
See the accompanying NOTICE file for attribution information.
## Goals
The primary goal of this module is deterministic reproduction of the
historical System.Random behavior used by Mono-based runtimes.
Given the same seed and the same sequence of API calls, compatible
implementations are expected to produce the same pseudorandom sequence.
## Intended Use Cases
- Runtime behavior analysis
- Cross-language tooling
- Automated testing
## Non-Goals
This implementation is not intended for cryptographic,
security-sensitive, or adversarial environments.
The underlying algorithm is designed for repeatability and statistical
usefulness rather than cryptographic security.
## Algorithm
This module implements a subtractive random number generator.
The generator maintains an internal state consisting of:
- A 56-element integer state array
- Two moving state indices
- A subtraction-based recurrence relation used to produce the next value
Each generated value is derived from the difference between two previously
stored state values. The resulting value is normalized into the valid integer
range and written back into the state array, forming the basis for subsequent
outputs.
"""
from __future__ import annotations
from typing import Final, overload
class MonoSystemRandom:
"""
A subtractive random number generator with a 56-element state array.
The algorithm maintains two moving indices into the state array and
generates each output from the difference of two previously stored values.
Generated values are fed back into the state array, producing a
deterministic pseudorandom sequence from an initial seed.
"""
_MBIG: Final[int] = 2_147_483_647
_MSEED: Final[int] = 161_803_398
_seed_array: list[int]
_inext: int
_inextp: int
def __init__(self, seed: int) -> None:
"""
Initialize the generator state from an integer seed.
"""
self._seed_array = [0] * 56
subtraction = self._MBIG if seed == -2_147_483_648 else abs(seed)
mj = self._MSEED - subtraction
if mj < 0:
mj += self._MBIG
self._seed_array[55] = mj
mk = 1
for i in range(1, 55):
ii = (21 * i) % 55
self._seed_array[ii] = mk
mk = mj - mk
if mk < 0:
mk += self._MBIG
mj = self._seed_array[ii]
for _ in range(4):
for i in range(1, 56):
self._seed_array[i] -= self._seed_array[
1 + (i + 30) % 55
]
if self._seed_array[i] < 0:
self._seed_array[i] += self._MBIG
self._inext = 0
self._inextp = 21
def _internal_sample(self) -> int:
"""
Generate a raw integer sample.
Returns:
An integer satisfying:
0 <= value < 2_147_483_647
"""
loc_inext = self._inext + 1
if loc_inext >= 56:
loc_inext = 1
loc_inextp = self._inextp + 1
if loc_inextp >= 56:
loc_inextp = 1
result = (
self._seed_array[loc_inext]
- self._seed_array[loc_inextp]
)
if result == self._MBIG:
result -= 1
if result < 0:
result += self._MBIG
self._seed_array[loc_inext] = result
self._inext = loc_inext
self._inextp = loc_inextp
return result
def _sample(self) -> float:
"""
Generate a floating-point sample in the half-open range:
0.0 <= value < 1.0
"""
return self._internal_sample() * (1.0 / self._MBIG)
def _get_sample_for_large_range(self) -> float:
"""
Generate a floating-point sample suitable for ranges wider than MBIG.
One sample determines magnitude and another determines sign,
expanding the effective sampling range.
"""
result = self._internal_sample()
if self._internal_sample() % 2 == 0:
result = -result
d = result + (self._MBIG - 1)
return d / (2 * self._MBIG - 1)
@overload
def next(self) -> int: ...
@overload
def next(self, max_value: int) -> int: ...
@overload
def next(self, min_value: int, max_value: int) -> int: ...
def next(
self,
min_value: int | None = None,
max_value: int | None = None,
) -> int:
"""
Generate an integer sample.
Supported call forms:
next()
next(max_value)
next(min_value, max_value)
For bounded calls, max_value is exclusive.
"""
if min_value is None and max_value is None:
return self._internal_sample()
if max_value is None:
max_value = min_value
min_value = 0
if max_value < 0:
raise ValueError("max_value must be >= 0")
if min_value > max_value:
raise ValueError("min_value must be <= max_value")
span = max_value - min_value
if span <= self._MBIG:
return int(self._sample() * span) + min_value
return int(self._get_sample_for_large_range() * span) + min_value
def next_double(self) -> float:
"""
Generate a floating-point sample in the half-open range:
0.0 <= value < 1.0
"""
return self._sample()
def next_bytes(self, length: int) -> bytes:
"""
Generate a bytes object of the requested length.
Each output byte is derived from one raw integer sample.
"""
if length < 0:
raise ValueError("length must be >= 0")
return bytes(
self._internal_sample() % 256
for _ in range(length)
)
MIT License
Copyright (c) Microsoft Corporation
Copyright (c) 2026 aoirint
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This project contains a Python port of the .NET Framework 4.6.2
Reference Source implementation of System.Random.
Reference:
https://github.com/microsoft/referencesource/blob/4fe4349175f4c5091d972a7e56ea12012f1e7170/mscorlib/system/random.cs
Copyright (c) Microsoft Corporation
Modifications and Python port:
Copyright (c) 2026 aoirint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment