< Summary

Class:GDX.Mathematics.Random.WELL1024a
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/Mathematics/Random/WELL1024a.cs
Covered lines:118
Uncovered lines:0
Coverable lines:118
Total lines:330
Line coverage:100% (118 of 118)
Covered branches:0
Total branches:0
Covered methods:19
Total methods:19
Method coverage:100% (19 of 19)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WELL1024a(...)0%220100%
WELL1024a(...)0%220100%
WELL1024a(...)0%330100%
WELL1024a(...)0%220100%
GetState()0%110100%
NextBoolean(...)0%110100%
NextBytes(...)0%220100%
NextDouble(...)0%110100%
NextInteger(...)0%110100%
NextIntegerExclusive(...)0%110100%
NextSingle(...)0%110100%
NextUnsignedInteger(...)0%110100%
NextUnsignedIntegerExclusive(...)0%110100%
Sample()0%110100%
Dispose()0%110100%
Equals(...)0%330100%
Equals(...)0%330100%
Equals(...)0%220100%
GetHashCode()0%110100%

File(s)

./Packages/com.dotbunny.gdx/GDX/Mathematics/Random/WELL1024a.cs

#LineLine coverage
 1// Copyright (c) 2020-2024 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using System.Runtime.CompilerServices;
 7using Unity.Collections;
 8using Unity.Collections.LowLevel.Unsafe;
 9using Unity.Mathematics;
 10
 11namespace GDX.Mathematics.Random
 12{
 13    // ReSharper disable CommentTypo
 14    /// <summary>
 15    ///     Generates pseudorandom values based on the WELL1024a algorithm. You must <see cref="Dispose" /> manually.
 16    /// </summary>
 17    /// <remarks>
 18    ///     Primarily based on the work of <a href="http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf">Chris Lomont</a>
 19    ///     accessed on 2021-04-23.
 20    ///     Additional understanding from
 21    ///     <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/lfsr04.pdf">Francois Panneton and Pierre L`Ecuyer
 22    ///     accessed on 2021-04-23.
 23    /// </remarks>
 24    // ReSharper restore CommentTypo
 25    [VisualScriptingCompatible(4)]
 26#pragma warning disable IDE1006
 27    // ReSharper disable once InconsistentNaming
 28    public unsafe struct WELL1024a : IRandomProvider, IEquatable<WELL1024a>, IDisposable
 29#pragma warning restore IDE1006
 30    {
 31        /// <summary>
 32        ///     The state array of the well.
 33        /// </summary>
 34        public NativeArray<uint> State;
 35
 36        /// <summary>
 37        ///     A copy of the original seed used to initialize the <see cref="WELL1024a" />.
 38        /// </summary>
 39        public readonly uint OriginalSeed;
 40
 41        /// <summary>
 42        ///     The number of times that this well has been sampled.
 43        /// </summary>
 44        public uint SampleCount;
 45
 46        /// <summary>
 47        ///     The current index of use for the well array.
 48        /// </summary>
 49        /// <remarks>CAUTION! Changing this will alter the understanding of the data.</remarks>
 50        public byte Index;
 51
 52        /// <summary>
 53        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 54        /// </summary>
 55        /// <remarks>
 56        ///     The <paramref name="seed" /> will have its sign stripped and stored as such in
 57        ///     <see cref="OriginalSeed" />.
 58        /// </remarks>
 59        /// <param name="seed">A <see cref="int" /> value to use as a seed.</param>
 60        public WELL1024a(int seed)
 161        {
 162            OriginalSeed = (uint)math.abs(seed);
 63
 64            // Initialize
 165            Index = 0;
 166            SampleCount = 0;
 167            State = new NativeArray<uint>(32, Allocator.Persistent);
 168            uint* ptr = (uint*)State.GetUnsafePtr();
 169            ptr[0] = OriginalSeed & 4294967295u;
 6470            for (int i = 1; i < 32; ++i)
 3171            {
 3172                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 3173            }
 174        }
 75
 76        /// <summary>
 77        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 78        /// </summary>
 79        /// <param name="seed">A <see cref="uint" /> value to use as a seed.</param>
 80        public WELL1024a(uint seed)
 381        {
 382            OriginalSeed = seed;
 83
 84            // Initialize
 385            Index = 0;
 386            SampleCount = 0;
 387            State = new NativeArray<uint>(32, Allocator.Persistent);
 388            uint* ptr = (uint*)State.GetUnsafePtr();
 389            ptr[0] = OriginalSeed & 4294967295u;
 19290            for (int i = 1; i < 32; ++i)
 9391            {
 9392                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 9393            }
 394        }
 95
 96        /// <summary>
 97        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 98        /// </summary>
 99        /// <remarks>
 100        ///     The created hashcode will have its sign stripped and stored as such in
 101        ///     <see cref="OriginalSeed" />.
 102        /// </remarks>
 103        /// <param name="seed">A <see cref="string" /> to create a <see cref="uint" /> seed from.</param>
 104        /// <param name="forceUpperCase">
 105        ///     Should the generated hashcode used as the seed be generated from an uppercase version of
 106        ///     the <paramref name="seed" />.
 107        /// </param>
 108        public WELL1024a(string seed, bool forceUpperCase = true)
 32109        {
 32110            if (forceUpperCase)
 30111            {
 30112                OriginalSeed = (uint)math.abs(seed.GetStableUpperCaseHashCode());
 30113            }
 114            else
 2115            {
 2116                OriginalSeed = (uint)math.abs(seed.GetStableHashCode());
 2117            }
 118
 119            // Initialize
 32120            Index = 0;
 32121            SampleCount = 0;
 32122            State = new NativeArray<uint>(32, Allocator.Persistent);
 32123            uint* ptr = (uint*)State.GetUnsafePtr();
 32124            ptr[0] = OriginalSeed & 4294967295u;
 2048125            for (int i = 1; i < 32; ++i)
 992126            {
 992127                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 992128            }
 32129        }
 130
 131        /// <summary>
 132        ///     Create a pseudorandom number generator from a <paramref name="restoreState" />.
 133        /// </summary>
 134        /// <param name="restoreState">A saved <see cref="WELL1024a" /> state.</param>
 135        public WELL1024a(WellState restoreState)
 2136        {
 2137            OriginalSeed = restoreState.Seed;
 2138            Index = restoreState.Index;
 139            // Create new native array
 2140            State = new NativeArray<uint>(32, Allocator.Persistent);
 2141            uint* ptr = (uint*)State.GetUnsafePtr();
 2142            uint* restoreStatePtr = (uint*)restoreState.State.GetUnsafePtr();
 132143            for (int i = 0; i < 32; i++)
 64144            {
 64145                ptr[i] = restoreStatePtr[i];
 64146            }
 147
 2148            SampleCount = restoreState.Count;
 2149        }
 150
 151        /// <summary>
 152        ///     Get a <see cref="WellState" /> for the <see cref="WELL1024a" />.
 153        /// </summary>
 154        /// <remarks>Useful to save and restore the state of the <see cref="WELL1024a" />.</remarks>
 155        /// <returns></returns>
 156        public WellState GetState()
 2157        {
 2158            return new WellState { Index = Index, State = State, Seed = OriginalSeed, Count = SampleCount };
 2159        }
 160
 161        /// <inheritdoc cref="IRandomProvider.NextBoolean" />
 162        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 163        public bool NextBoolean(float chance = 0.5f)
 3164        {
 3165            return Sample() <= chance;
 3166        }
 167
 168        /// <inheritdoc cref="IRandomProvider.NextBytes" />
 169        public void NextBytes(byte[] buffer)
 4170        {
 4171            int bufLen = buffer.Length;
 68172            for (int idx = 0; idx < bufLen; ++idx)
 30173            {
 30174                buffer[idx] = (byte)NextInteger(0, 256);
 30175            }
 4176        }
 177
 178        /// <inheritdoc cref="IRandomProvider.NextDouble" />
 179        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 180        public double NextDouble(double minValue = 0d, double maxValue = 1d)
 67181        {
 67182            return Range.GetDouble(Sample(), minValue, maxValue);
 67183        }
 184
 185        /// <inheritdoc cref="IRandomProvider.NextInteger" />
 186        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 187        public int NextInteger(int minValue = 0, int maxValue = int.MaxValue)
 124188        {
 124189            return Range.GetInteger(Sample(), minValue, maxValue);
 124190        }
 191
 192        /// <inheritdoc cref="IRandomProvider.NextIntegerExclusive" />
 193        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 194        public int NextIntegerExclusive(int minValue = 0, int maxValue = int.MaxValue)
 26195        {
 26196            return Range.GetInteger(Sample(), minValue + 1, maxValue - 1);
 26197        }
 198
 199        /// <inheritdoc cref="IRandomProvider.NextSingle" />
 200        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 201        public float NextSingle(float minValue = 0f, float maxValue = 1f)
 65202        {
 65203            return Range.GetSingle(Sample(), minValue, maxValue);
 65204        }
 205
 206        /// <inheritdoc cref="IRandomProvider.NextUnsignedInteger" />
 207        public uint NextUnsignedInteger(uint minValue = uint.MinValue, uint maxValue = uint.MaxValue)
 65208        {
 65209            return Range.GetUnsignedInteger(Sample(), minValue, maxValue);
 65210        }
 211
 212        /// <inheritdoc cref="IRandomProvider.NextUnsignedIntegerExclusive" />
 213        public uint NextUnsignedIntegerExclusive(uint minValue = uint.MinValue, uint maxValue = uint.MaxValue)
 2214        {
 2215            return Range.GetUnsignedInteger(Sample(), minValue + 1, maxValue - 1);
 2216        }
 217
 218        /// <inheritdoc cref="IRandomProvider.Sample" />
 219        public double Sample()
 355220        {
 355221            SampleCount++;
 222
 355223            uint* ptr = (uint*)State.GetUnsafePtr();
 355224            uint a = ptr[(int)((Index + 3u) & 31u)];
 355225            uint z1 = ptr[Index] ^ a ^ (a >> 8);
 355226            uint b = ptr[(int)((Index + 24u) & 31u)];
 355227            uint c = ptr[(int)((Index + 10u) & 31u)];
 355228            uint z2 = b ^ (b << 19) ^ c ^ (c << 14);
 229
 355230            ptr[Index] = z1 ^ z2;
 355231            uint d = ptr[(int)((Index + 31u) & 31u)];
 355232            ptr[(int)((Index + 31u) & 31u)] = d ^ (d << 11) ^ z1 ^ (z1 << 7) ^ z2 ^ (z2 << 13);
 355233            Index = (byte)((Index + 31u) & 31u);
 234
 355235            return ptr[Index & 31u] * 2.32830643653869628906e-10d;
 355236        }
 237
 238        /// <summary>
 239        ///     A complete state of <see cref="WELL1024a" />.
 240        /// </summary>
 241        [Serializable]
 242        public struct WellState
 243        {
 244            /// <summary>
 245            ///     The seed used to originally create the <see cref="WELL1024a" />.
 246            /// </summary>
 247            public uint Seed;
 248
 249            /// <summary>
 250            ///     The internal sample count.
 251            /// </summary>
 252            public uint Count;
 253
 254            /// <summary>
 255            ///     The internal state index.
 256            /// </summary>
 257            public byte Index;
 258
 259            /// <summary>
 260            ///     The internal state array.
 261            /// </summary>
 262            public NativeArray<uint> State;
 263        }
 264
 265        /// <summary>
 266        ///     Disposes of the native allocations.
 267        /// </summary>
 268        public void Dispose()
 36269        {
 36270            State.Dispose();
 36271        }
 272
 273        /// <summary>
 274        ///     Is one <see cref="WELL1024a" /> the same as the <paramref name="other" />.
 275        /// </summary>
 276        /// <param name="other">The <see cref="WELL1024a" /> to compare with.</param>
 277        /// <returns>true/false if they are fundamentally the same.</returns>
 278        public bool Equals(ref WELL1024a other)
 1279        {
 1280            return OriginalSeed == other.OriginalSeed &&
 281                   Index == other.Index &&
 282                   SampleCount == other.SampleCount;
 1283        }
 284
 285        /// <summary>
 286        ///     Is one <see cref="WELL1024a" /> the same as the <paramref name="other" />.
 287        /// </summary>
 288        /// <remarks>
 289        ///     Avoid using this format for comparison as it copies the data, where as
 290        ///     <see cref="Equals(ref GDX.Mathematics.Random.WELL1024a)" /> does not.
 291        /// </remarks>
 292        /// <param name="other">The <see cref="WELL1024a" /> to compare with.</param>
 293        /// <returns>true/false if they are fundamentally the same.</returns>
 294        public bool Equals(WELL1024a other)
 1295        {
 1296            return OriginalSeed == other.OriginalSeed &&
 297                   Index == other.Index &&
 298                   SampleCount == other.SampleCount;
 1299        }
 300
 301        /// <summary>
 302        ///     Determines if the provided <paramref name="obj" />'s hash code is equal to this <see cref="WELL1024a" />
 303        ///     <see cref="GetHashCode" />.
 304        /// </summary>
 305        /// <remarks>
 306        ///     This doesnt preclude other objects of different types from having the same hashcode.
 307        /// </remarks>
 308        /// <param name="obj">The <see cref="object" /> to compare hash codes with.</param>
 309        /// <returns>true/false if the hash codes match.</returns>
 310        public override bool Equals(object obj)
 1311        {
 1312            return obj != null && GetHashCode() == obj.GetHashCode();
 1313        }
 314
 315        /// <summary>
 316        ///     Generate a hash code value for the given <see cref="WELL1024a" /> at its current state.
 317        /// </summary>
 318        /// <returns>The hash code value.</returns>
 319        public override int GetHashCode()
 2320        {
 321            unchecked
 2322            {
 2323                int hashCode = (int)OriginalSeed;
 2324                hashCode = (hashCode * 397) ^ Index;
 2325                hashCode = (hashCode * 397) ^ (int)SampleCount;
 2326                return hashCode;
 327            }
 2328        }
 329    }
 330}

Coverage by test methods










































Methods/Properties

WELL1024a(System.Int32)
WELL1024a(System.UInt32)
WELL1024a(System.String, System.Boolean)
WELL1024a(GDX.Mathematics.Random.WELL1024a/WellState)
GetState()
NextBoolean(System.Single)
NextBytes(System.Byte[])
NextDouble(System.Double, System.Double)
NextInteger(System.Int32, System.Int32)
NextIntegerExclusive(System.Int32, System.Int32)
NextSingle(System.Single, System.Single)
NextUnsignedInteger(System.UInt32, System.UInt32)
NextUnsignedIntegerExclusive(System.UInt32, System.UInt32)
Sample()
Dispose()
Equals(GDX.Mathematics.Random.WELL1024a&)
Equals(GDX.Mathematics.Random.WELL1024a)
Equals(System.Object)
GetHashCode()