class · System

Random

public class Random

Pseudo-random numbers. new Random(seed) gives the same numbers for the same seed; new Random() and Random.Shared are seeded from the clock (and a counter, so two made at once differ). Not for secrets.

Kind
class
Namespace
System
Assembly
System.Core
Access
public
Source file
Random.ant

Inheritance

Base classes
Any Random

Constructors

new()
#

Seeded from the clock.

new(i32 seed)
#

The same numbers for the same seed.

Properties

static Random Shared { get; }
#

static read-only

One shared generator (seeded from the clock).

Methods

NextUInt64() : u64
#

64 random bits.

Next() : i32
#

From 0 up to (not including) Int32.MaxValue.

Next(i32 max) : i32
#

From 0 up to (not including) max (0 when max is 0).

Next(i32 min, i32 max) : i32
#

From min up to (not including) max (min when they are equal).

NextInt64() : i64
#

From 0 up to (not including) Int64.MaxValue.

NextInt64(i64 max) : i64
#

From 0 up to (not including) max.

NextInt64(i64 min, i64 max) : i64
#

From min up to (not including) max.

NextDouble() : f64
#

From 0 up to (not including) 1, in steps of 2^-53.

NextSingle() : f32
#

From 0 up to (not including) 1, in steps of 2^-24.

NextBytes(u8[] buffer)
#

Fills buffer with random bytes.

Shuffle<T>(T[] items)
#

Puts the elements in a random order (Fisher–Yates: every order as likely).

Private and internal members (10)

u64 s0
#

private

u64 s1
#

private

u64 s2
#

private

u64 s3
#

private

static u64 made
#

private static

static Random? shared
#

private static

Seed(u64 seed)
#

private

SplitMix64: spreads a seed over the four words of the state (never all zero).

static Mix(u64 z) : u64
#

private static

Below(u32 bound) : u32
#

private

Values below bound (> 0), all as likely: the high half of a 64-bit product (Lemire), retried in the rare band that would favour some values.

Below64(u64 bound) : u64
#

private

Values below bound (> 0), all as likely: masked draws, retried when past the bound.

Inherited members (5)

Source

Random as Antril, decompiled from its Larva HIR.

System.Random.ant
// System.Random — System.Core (decompiled from Larva HIR)

into namespace System
{
	/// Pseudo-random numbers. `new Random(seed)` gives the same numbers for the same seed; `new Random()` and
	/// `Random.Shared` are seeded from the clock (and a counter, so two made at once differ). Not for secrets.
	public class Random
	{
		u64 s0;
		u64 s1;
		u64 s2;
		u64 s3;
		static u64 made;
		static Random? shared;

		/// SplitMix64: spreads a seed over the four words of the state (never all zero).
		Seed(u64 seed)
		{
			u64 x = seed;
			x += 11400714819323198485;
			s0 = Mix(x);
			x += 11400714819323198485;
			s1 = Mix(x);
			x += 11400714819323198485;
			s2 = Mix(x);
			x += 11400714819323198485;
			s3 = Mix(x);
		}

		static Mix(u64 z) : u64
		{
			z = (z ^ z >> 30) * 13787848793156543929;
			z = (z ^ z >> 27) * 10723151780598845931;
			return z ^ z >> 31;
		}

		/// Values below `bound` (> 0), all as likely: the high half of a 64-bit product (Lemire), retried in the rare
		/// band that would favour some values.
		Below(u32 bound) : u32
		{
			u64 product = (u64)(u32)(NextUInt64() >> 32) * (u64)bound;
			u32 low = (u32)product;
			if (low < bound)
			{
				u32 threshold = (0 - bound) % bound;
				loop (low < threshold)
				{
					product = (u64)(u32)(NextUInt64() >> 32) * (u64)bound;
					low = (u32)product;
				}
			}
			return (u32)(product >> 32);
		}

		/// Values below `bound` (> 0), all as likely: masked draws, retried when past the bound.
		Below64(u64 bound) : u64
		{
			u64 mask = bound - 1;
			mask |= mask >> 1;
			mask |= mask >> 2;
			mask |= mask >> 4;
			mask |= mask >> 8;
			mask |= mask >> 16;
			mask |= mask >> 32;
			u64 value = NextUInt64() & mask;
			loop (value >= bound)
				value = NextUInt64() & mask;
			return value;
		}

		public:
			/// Seeded from the clock.
			new()
			{
				made++;
				Seed((u64)Environment.TickCount64 * 2685821657736338717 ^ made * 11400714819323198485);
			}

			/// The same numbers for the same seed.
			new(i32 seed)
			{
				Seed((u64)seed);
			}

			/// 64 random bits.
			NextUInt64() : u64
			{
				u64 result = s1 * 5;
				result = (result << 7 | result >> 57) * 9;
				u64 t = s1 << 17;
				s2 ^= s0;
				s3 ^= s1;
				s1 ^= s2;
				s0 ^= s3;
				s2 ^= t;
				s3 = s3 << 45 | s3 >> 19;
				return result;
			}

			/// From 0 up to (not including) Int32.MaxValue.
			Next() : i32
			{
				u32 value = (u32)(NextUInt64() >> 33);
				loop (value == 2147483647)
					value = (u32)(NextUInt64() >> 33);
				return (i32)value;
			}

			/// From 0 up to (not including) `max` (0 when max is 0).
			Next(i32 max) : i32
			{
				if (max < 0)
					throw new ArgumentError("Random.Next: the maximum is negative");
				return max <= 1 ? 0 : (i32)Below((u32)max);
			}

			/// From `min` up to (not including) `max` (min when they are equal).
			Next(i32 min, i32 max) : i32
			{
				if (min > max)
					throw new ArgumentError("Random.Next: the minimum is past the maximum");
				u32 range = (u32)((i64)max - (i64)min);
				return range <= 1 ? min : (i32)((i64)min + (i64)Below(range));
			}

			/// From 0 up to (not including) Int64.MaxValue.
			NextInt64() : i64
			{
				u64 value = NextUInt64() >> 1;
				loop (value == 9223372036854775807)
					value = NextUInt64() >> 1;
				return (i64)value;
			}

			/// From 0 up to (not including) `max`.
			NextInt64(i64 max) : i64
			{
				if (max < 0)
					throw new ArgumentError("Random.NextInt64: the maximum is negative");
				return max <= 1 ? 0 : (i64)Below64((u64)max);
			}

			/// From `min` up to (not including) `max`.
			NextInt64(i64 min, i64 max) : i64
			{
				if (min > max)
					throw new ArgumentError("Random.NextInt64: the minimum is past the maximum");
				u64 range = (u64)max - (u64)min;
				return range <= 1 ? min : (i64)((u64)min + Below64(range));
			}

			/// From 0 up to (not including) 1, in steps of 2^-53.
			NextDouble() : f64 => (f64)(NextUInt64() >> 11) * 1.1102230246251565E-16;

			/// From 0 up to (not including) 1, in steps of 2^-24.
			NextSingle() : f32 => (f32)(NextUInt64() >> 40) * 5.960464477539063E-08;

			/// Fills `buffer` with random bytes.
			NextBytes(u8[] buffer)
			{
				i32 i = 0;
				loop (i + 8 <= buffer.Length)
				{
					u64 bits = NextUInt64();
					loop (i32 k = 0..8)
					{
						buffer[i + k] = (u8)bits;
						bits = bits >> 8;
					}
					i += 8;
				}
				if (i < buffer.Length)
				{
					u64 rest = NextUInt64();
					loop (i < buffer.Length)
					{
						buffer[i] = (u8)rest;
						rest = rest >> 8;
						i++;
					}
				}
			}

			/// Puts the elements in a random order (Fisher–Yates: every order as likely).
			Shuffle<T>(T[] items)
			{
				loop (i32 i = items.Length - 1; i > 0; i--)
				{
					i32 j = (i32)Below((u32)(i + 1));
					T held = items[i];
					items[i] = items[j];
					items[j] = held;
				}
			}

			/// One shared generator (seeded from the clock).
			static Random Shared
			{
				get
				{
					if (shared is Random known)
						return known;
					Random fresh = new Random();
					shared = fresh;
					return fresh;
				}
			}
	}
}
Esc