| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- using System;
- using System.Runtime.CompilerServices;
- using Microsoft.Xna.Framework;
- namespace MonoGame.Extended
- {
- /// <summary>
- /// Represents a pseudo-random number generator using a linear congruential generator algorithm.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This implementation uses the same constants as Microsoft Visual C++ rand() function:
- ///
- /// a=214013
- /// c=2531011
- /// m=2^31
- /// </para>
- /// <para>
- /// It provides high performance and speed, but comes at the price of having lower statistical quality, or true
- /// 'randomness' compared to modern algorithms. The algorithm is deterministic based on the initial seed
- /// value, making it suitable for reproducible sequences.
- ///</para>
- ///<para>
- /// Note: This pseudo-random number generator exhibits noticeable patterns and should not be used for
- /// cryptographic purposes or when a high-quality random distribution is critical. Consider using
- /// <see cref="System.Random"/> for better statistical properties.
- /// </para>
- /// </remarks>
- public class FastRandom
- {
- private readonly IFastRandomImpl _impl;
- /// <summary>
- /// Provides a thread-safe <see cref="FastRandom"/> instance that may be used concurrently from any thread.
- /// </summary>
- public static FastRandom Shared { get; } = new FastRandom(new ThreadSafeFastRandomImpl());
- /// <summary>
- /// Initializes a new instance of the <see cref="FastRandom"/> class using the default seed value.
- /// </summary>
- public FastRandom() : this(1)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="FastRandom"/> class using the specified seed value.
- /// </summary>
- /// <param name="seed">A number used to calculate a starting value for the pseudo-random number sequence.</param>
- public FastRandom(int seed)
- {
- _impl = new LinearCongruentialGeneratorImpl(seed);
- }
- private FastRandom(IFastRandomImpl impl)
- {
- ArgumentNullException.ThrowIfNull(impl);
- _impl = impl;
- }
- /// <summary>
- /// Returns a non-negative random integer.
- /// </summary>
- /// <returns>A 32-bit signed integer that is greater than or equal to 0 and less than 32768.</returns>
- public int Next()
- {
- return _impl.Next();
- }
- /// <summary>
- /// Returns a non-negative random integer that is less than or equal to the specified maximum.
- /// </summary>
- /// <param name="max">The inclusive upper bound of the random number to be generated.</param>
- /// <returns>
- /// A 32-bit signed integer that is greater than or equal to 0 and less than or equal to <paramref name="max"/>.
- /// </returns>
- public int Next(int max)
- {
- return _impl.Next(max);
- }
- /// <summary>
- /// Returns a random integer that is within a specified range.
- /// </summary>
- /// <param name="min">The inclusive lower bound of the random number returned.</param>
- /// <param name="max">The inclusive upper bound of the random number returned.</param>
- /// <returns>
- /// A 32-bit signed integer that is greater than or equal to <paramref name="min"/> and less than or equal to
- /// <paramref name="max"/>.
- /// </returns>
- public int Next(int min, int max)
- {
- return _impl.Next(min, max);
- }
- /// <summary>
- /// Returns a random integer that is within a specified range.
- /// </summary>
- /// <param name="range">
- /// A range representing the inclusive lower and upper bound of the random number to return.
- /// </param>
- /// <returns>
- /// A 32-bit signed integer that is greater than or equal to the <see cref="Range{T}.Min"/> and less than or
- /// equal to the <see cref="Range{T}.Max"/> value of <paramref name="range"/>.
- /// </returns>
- [Obsolete("Use Next(Interval<int>). Range<T> will be removed in 6.0")]
- public int Next(Range<int> range)
- {
- return _impl.Next(range);
- }
- /// <summary>
- /// Returns a random integer that is within a closed interval.
- /// </summary>
- /// <param name="interval">
- /// A closed interval representing the lower and upper bounds of the random number to return.
- /// </param>
- /// <returns>
- /// A 32-bit signed integer that is greater than or equal to the <see cref="Interval{T}.Min"/> value and less
- /// than or equal to the <see cref="Interval{T}.Max"/> value of <paramref name="interval"/>.
- /// </returns>
- public int Next(Interval<int> interval)
- {
- return _impl.Next(interval);
- }
- /// <summary>
- /// Returns a random floating-point number that is greater than or equal to 0.0 and less than 1.0.
- /// </summary>
- /// <returns>
- /// A single-precision floating point number that is greater than or equal to 0.0 and less than 1.0.
- /// </returns>
- public float NextSingle()
- {
- return _impl.NextSingle();
- }
- /// <summary>
- /// Returns a random floating-point number that is greater than or equal to 0.0 and less than the
- /// specified maximum.
- /// </summary>
- /// <param name="max">The exclusive upper bond of the random number generated.</param>
- /// <returns>
- /// A single precision floating-point number that is greater than or equal to 0.0 and less than
- /// <paramref name="max"/>.
- /// </returns>
- public float NextSingle(float max)
- {
- return _impl.NextSingle(max);
- }
- /// <summary>
- /// Returns a random floating-point number that is within a specified range.
- /// </summary>
- /// <param name="min">The inclusive lower bound of the random number returned.</param>
- /// <param name="max">The exclusive upper bound of the random number returned.</param>
- /// <returns>
- /// A single-precision floating point number that is greater than or equal to <paramref name="min"/> and
- /// less than <paramref name="max"/>.
- /// </returns>
- public float NextSingle(float min, float max)
- {
- return _impl.NextSingle(min, max);
- }
- /// <summary>
- /// Returns a random floating-point number that is within a specified range.
- /// </summary>
- /// <param name="range">
- /// A range representing the inclusive lower and exclusive upper bound of the random number returned.
- /// </param>
- /// <returns>
- /// A single-precision floating point number that is greater than or equal to the <see cref="Range{T}.Min"/>
- /// and less than the <see cref="Range{T}.Max"/> value of <paramref name="range"/>
- /// </returns>
- [Obsolete("Use Next(Interval<float>). Range<T> will be removed in 6.0")]
- public float NextSingle(Range<float> range)
- {
- return _impl.NextSingle(range);
- }
- /// <summary>
- /// Returns a random floating-point number that is within a closed interval.
- /// </summary>
- /// <param name="interval">
- /// A closed interval representing the lower and upper bounds of the random number to return.
- /// </param>
- /// <returns>
- /// A single-precision floating point number that is greater than or equal to the <see cref="Interval{T}.Min"/>
- /// value and less than or equal to the <see cref="Interval{T}.Max"/> value of <paramref name="interval"/>.
- /// </returns>
- public float NextSingle(Interval<float> interval)
- {
- return _impl.NextSingle(interval);
- }
- /// <summary>
- /// Returns a random angle between -π and π.
- /// </summary>
- /// <returns>
- /// A random angle value in radians.
- /// </returns>
- public float NextAngle()
- {
- return _impl.NextAngle();
- }
- /// <summary>
- /// Gets a random unit vector.
- /// </summary>
- /// <param name="vector">When this method returns, contains a unit vector with a random direction.</param>
- public void NextUnitVector(out Vector2 vector)
- {
- _impl.NextUnitVector(out vector);
- }
- /// <summary>
- /// Gets a random unit vector.
- /// </summary>
- /// <param name="vector">A pointer to the Vector2 where the random unit vector will be stored.</param>
- public unsafe void NextUnitVector(Vector2* vector)
- {
- _impl.NextUnitVector(vector);
- }
- #region IFastRandomImplementation
- private interface IFastRandomImpl
- {
- int Next();
- int Next(int max);
- int Next(int min, int max);
- [Obsolete("Use Next(Interval<int>). Range<T> will be removed in 6.0")]
- int Next(Range<int> range);
- int Next(Interval<int> interval);
- float NextSingle();
- float NextSingle(float max);
- float NextSingle(float min, float max);
- [Obsolete("Use Next(Interval<float>). Range<T> will be removed in 6.0")]
- float NextSingle(Range<float> range);
- float NextSingle(Interval<float> interval);
- float NextAngle();
- void NextUnitVector(out Vector2 vector);
- unsafe void NextUnitVector(Vector2* vector);
- }
- #endregion
- #region Linear Congruential Generator
- private sealed class LinearCongruentialGeneratorImpl : IFastRandomImpl
- {
- private const int MULTIPLIER = 214013;
- private const int INCREMENT = 2531011;
- private int _state;
- public LinearCongruentialGeneratorImpl() : this(1)
- {
- }
- public LinearCongruentialGeneratorImpl(int seed)
- {
- ArgumentOutOfRangeException.ThrowIfNegativeOrZero(seed);
- _state = seed;
- }
- public int Next()
- {
- _state = MULTIPLIER * _state + INCREMENT;
- return (_state >> 16) & 0x7FFF;
- }
- public int Next(int max)
- {
- return (int)(max * NextSingle() + 0.5f);
- }
- public int Next(int min, int max)
- {
- return (int)((max - min) * NextSingle() + 0.5f) + min;
- }
- [Obsolete("Use Next(Interval<int>). Range<T> will be removed in 6.0")]
- public int Next(Range<int> range)
- {
- return Next(range.Min, range.Max);
- }
- public int Next(Interval<int> interval)
- {
- return Next(interval.Min, interval.Max);
- }
- public float NextSingle()
- {
- return Next() / (float)short.MaxValue;
- }
- public float NextSingle(float max)
- {
- return max * NextSingle();
- }
- public float NextSingle(float min, float max)
- {
- return (max - min) * NextSingle() + min;
- }
- [Obsolete("Use Next(Interval<float>). Range<T> will be removed in 6.0")]
- public float NextSingle(Range<float> range)
- {
- return NextSingle(range.Min, range.Max);
- }
- public float NextSingle(Interval<float> interval)
- {
- return NextSingle(interval.Min, interval.Max);
- }
- public float NextAngle()
- {
- return NextSingle(-MathHelper.Pi, MathHelper.Pi);
- }
- public void NextUnitVector(out Vector2 vector)
- {
- float angle = NextAngle();
- vector.X = MathF.Cos(angle);
- vector.Y = MathF.Sin(angle);
- }
- public unsafe void NextUnitVector(Vector2* vector)
- {
- float angle = NextAngle();
- vector->X = MathF.Cos(angle);
- vector->Y = MathF.Sin(angle);
- }
- }
- #endregion
- #region ThreadSafeImpl
- private sealed class ThreadSafeFastRandomImpl : IFastRandomImpl
- {
- [ThreadStatic]
- private static LinearCongruentialGeneratorImpl t_random;
- private static LinearCongruentialGeneratorImpl LocalRandom => t_random ?? Create();
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static LinearCongruentialGeneratorImpl Create()
- {
- t_random = new LinearCongruentialGeneratorImpl();
- return t_random;
- }
- public int Next()
- {
- return LocalRandom.Next();
- }
- public int Next(int max)
- {
- return LocalRandom.Next(max);
- }
- public int Next(int min, int max)
- {
- return LocalRandom.Next(min, max);
- }
- [Obsolete("Use Next(Interval<int>). Range<T> will be removed in 6.0")]
- public int Next(Range<int> range)
- {
- return LocalRandom.Next(range.Min, range.Max);
- }
- public int Next(Interval<int> interval)
- {
- return LocalRandom.Next(interval.Min, interval.Max);
- }
- public float NextSingle()
- {
- return LocalRandom.NextSingle();
- }
- public float NextSingle(float max)
- {
- return LocalRandom.NextSingle(max);
- }
- public float NextSingle(float min, float max)
- {
- return LocalRandom.NextSingle(min, max);
- }
- [Obsolete("Use Next(Interval<float>). Range<T> will be removed in 6.0")]
- public float NextSingle(Range<float> range)
- {
- return LocalRandom.NextSingle(range.Min, range.Max);
- }
- public float NextSingle(Interval<float> interval)
- {
- return LocalRandom.NextSingle(interval.Min, interval.Max);
- }
- public float NextAngle()
- {
- return LocalRandom.NextAngle();
- }
- public void NextUnitVector(out Vector2 vector)
- {
- LocalRandom.NextUnitVector(out vector);
- }
- public unsafe void NextUnitVector(Vector2* vector)
- {
- LocalRandom.NextUnitVector(vector);
- }
- }
- #endregion
- }
- }
|