using System; namespace MagmaEngine.Math; /// /// Implements a XorShift* PRNG, with 64 bits of internal state. /// See http://en.wikipedia.org/wiki/Xorshift /// public struct SIntRandom { public SIntRandom(ulong seed) { if (seed == 0) throw new InvalidOperationException("Seed needs to be bigger than zero."); m_Seed = seed; } public ulong Next() { m_Seed ^= m_Seed >> 12; m_Seed ^= m_Seed << 25; m_Seed ^= m_Seed >> 27; return m_Seed * 2685821657736338717UL; // multiplier taken from wikipedia article on XorShift PRNGs } public ulong Next(ulong upperLimit) { if (upperLimit == 0) { return 0; } return Next() % upperLimit; } public FixPoint16 NextFixPoint16() { return new() { m_Value = (int)(Next() & 0xffffUL) }; } public int RandomizedRound(FixPoint16 value) { int ret = value.ToIntFloor(); if (NextFixPoint16() < FixPoint16.Fract(value)) ret++; return ret; } public uint Next(uint upperLimit) { if (upperLimit == 0) { return 0; } return (uint)(Next() % upperLimit); } public uint Next(uint lowerLimit, uint upperLimit) { if (upperLimit == 0) { return 0; } if (lowerLimit == upperLimit) { return lowerLimit; } return lowerLimit + (uint)(Next() % (upperLimit - lowerLimit)); } public int Next(int upperLimit) { if (upperLimit == 0) { return 0; } return (int)(Next() % (uint)(upperLimit & 0x7fffffff)); } public int Next(int lowerLimit, int upperLimit) { if (upperLimit == 0) { return 0; } if (lowerLimit == upperLimit) { return lowerLimit; } return lowerLimit + (int)(Next() % (uint)((upperLimit - lowerLimit) & 0x7fffffff)); } public double NextDouble() { return Next(int.MaxValue) * (1.0 / int.MaxValue); } public float NextSingle() { return (float)NextDouble(); } public override readonly string ToString() { return $"0x{m_Seed:X}"; } public readonly ulong Seed => m_Seed; private ulong m_Seed; }