// ==========================================================================================
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
// 均受中华人民共和国及相关国际法律法规保护。
// are protected by the laws of the People's Republic of China and relevant international regulations.
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
// 本项目采用 Apache License 2.0 单协议分发,
// This project is licensed solely under the Apache License 2.0,
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
// please refer to the LICENSE file in the root directory of the source code for the full license text.
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
// 侵犯他人合法权益等法律法规所禁止的行为!
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
// Any legal disputes and liabilities arising from secondary development based on this project
// 本项目组织与贡献者概不承担。
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
// GitHub 仓库:https://github.com/GameFrameX
// GitHub Repository: https://github.com/GameFrameX
// Gitee 仓库:https://gitee.com/GameFrameX
// Gitee Repository: https://gitee.com/GameFrameX
// CNB 仓库:https://cnb.cool/GameFrameX
// CNB Repository: https://cnb.cool/GameFrameX
// 官方文档:https://gameframex.doc.alianblank.com/
// Official Documentation: https://gameframex.doc.alianblank.com/
// ==========================================================================================
namespace GameFrameX.Utility.Math;
///
/// 生成基于确定性方法的随机数。
///
///
/// 梅森旋转(MT19937)伪随机:确定性可复现,但**非密码学安全**,
/// 不得用于令牌、验证码、防作弊抽奖等安全决策;安全场景请使用
/// System.Security.Cryptography.RandomNumberGenerator。
/// 静态共享实例不保证线程安全(状态推进无锁);需要并发隔离时用
/// 创建独立实例。
///
public sealed class FPRandom
{
// 来源:http://www.codeproject.com/Articles/164087/Random-Number-Generation
// TSRandom 类使用梅森旋转算法生成均匀分布的随机数。
private const int N = 624; // 状态向量的大小
private const int M = 397; // 子向量的大小
private const uint MATRIX_A = 0x9908b0dfU; // 变换矩阵的常量
private const uint UPPER_MASK = 0x80000000U; // 上半部分掩码
private const uint LOWER_MASK = 0x7fffffffU; // 下半部分掩码
private const int MAX_RAND_INT = 0x7fffffff; // 最大随机整数值
///
/// 使用种子 1 的 {@link TSRandom} 的静态实例。
///
///
/// 首次访问静态成员时懒初始化(种子 1,确定性序列),无需调用方先调用 。
///
private static FPRandom instance;
///
/// 静态成员使用的确定性实例;未初始化时按种子 1 创建(并发首次访问只发布一个实例)。
///
private static FPRandom Instance
{
get
{
var current = Volatile.Read(ref instance);
if (current != null)
{
return current;
}
var created = New(1);
return Interlocked.CompareExchange(ref instance, created, null) ?? created;
}
}
private readonly uint[] mag01 = { 0x0U, MATRIX_A, }; // 变换矩阵
private readonly uint[] mt = new uint[N]; // 梅森旋转状态向量
private int mti = N + 1; // 当前状态向量索引
///
/// 使用指定的种子初始化一个新的实例。
///
/// 用于初始化的种子。
private FPRandom(int seed)
{
init_genrand((uint)seed);
}
///
/// 使用指定的初始化数组初始化一个新的实例。
///
/// 初始化数组。
private FPRandom(int[] init)
{
var initArray = new uint[init.Length];
for (var i = 0; i < init.Length; ++i)
{
initArray[i] = (uint)init[i];
}
init_by_array(initArray, (uint)initArray.Length);
}
///
/// 获取最大随机整数值。
///
public static int MaxRandomInt
{
get { return 0x7fffffff; }
}
///
/// 返回一个 {@link FP} 值,范围在 0.0 [包含] 到 1.0 [包含] 之间。
///
public static FP value
{
get { return Instance.NextFP(); }
}
///
/// 返回一个随机的 {@link TSVector},表示半径为 1 的球体内的一个点。
///
///
/// 单位立方体拒绝采样:三个分量独立取 [-1, 1],模长超 1 则重采,
/// 结果在球体内均匀分布(旧实现返回的是立方体内的点)。
///
public static FPVector3 insideUnitSphere
{
get
{
while (true)
{
var candidate = new FPVector3(value * 2 - FP.One, value * 2 - FP.One, value * 2 - FP.One);
if (candidate.magnitude <= FP.One)
{
return candidate;
}
}
}
}
///
/// 显式重置静态实例为种子 1 的新序列(测试用)。
///
internal static void Init()
{
Interlocked.Exchange(ref instance, New(1));
}
///
/// 根据给定的种子生成一个新的实例。
///
/// 用于生成新实例的种子。
/// 新的 FPRandom 实例。
public static FPRandom New(int seed)
{
var r = new FPRandom(seed);
// StateTracker.AddTracking(r, "mt");
// StateTracker.AddTracking(r, "mti");
return r;
}
///
/// 返回一个随机整数。
///
/// 生成的随机整数。
public int Next()
{
return genrand_int31();
}
///
/// 返回一个随机整数。
///
/// 生成的随机整数。
public static int CallNext()
{
return Instance.Next();
}
///
/// 返回一个介于 minValue [包含] 和 maxValue [不包含] 之间的整数。
///
/// 最小值。
/// 最大值。
/// 生成的随机整数。minValue == maxValue 时返回 minValue。
public int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
(maxValue, minValue) = (minValue, maxValue);
}
var range = (ulong)((long)maxValue - minValue);
if (range == 0)
{
return minValue;
}
// 拒绝采样消除模偏:Next() ∈ [0, 2^31 - 1],只接受落在 range 整数倍内的样本。
var drawCount = (ulong)MaxRandomInt + 1;
if (range < drawCount)
{
var limit = drawCount - drawCount % range;
int draw;
do
{
draw = Next();
} while ((ulong)draw >= limit);
return (int)(minValue + (long)((ulong)draw % range));
}
// 跨度超过 31 位随机域(如 int.MinValue..int.MaxValue)时用 [0,1) 双精度缩放。
return (int)(minValue + (long)(NextDouble() * range));
}
///
/// 返回一个 {@link FP} 值,范围在 minValue [包含] 到 maxValue [包含] 之间。
///
/// 最小值。
/// 最大值。
/// 生成的随机 FP 值。
public FP Next(float minValue, float maxValue)
{
int minValueInt = (int)(minValue * 1000), maxValueInt = (int)(maxValue * 1000);
if (minValueInt > maxValueInt)
{
(maxValueInt, minValueInt) = (minValueInt, maxValueInt);
}
return FP.Floor((maxValueInt - minValueInt + 1) * NextFP() +
minValueInt) / 1000;
}
///
/// 返回一个介于 minValue [包含] 和 maxValue [不包含] 之间的整数。
///
/// 最小值。
/// 最大值。
/// 生成的随机整数。
public static int Range(int minValue, int maxValue)
{
return Instance.Next(minValue, maxValue);
}
///
/// 返回一个 {@link FP} 值,范围在 minValue [包含] 到 maxValue [包含] 之间。
///
/// 最小值。
/// 最大值。
/// 生成的随机 FP 值。
public static FP Range(float minValue, float maxValue)
{
return Instance.Next(minValue, maxValue);
}
///
/// 返回一个 {@link FP} 值,范围在 0.0 [包含] 到 1.0 [包含] 之间。
///
/// 生成的随机 FP 值。
public FP NextFP()
{
return (FP)Next() / MaxRandomInt;
}
private float NextFloat()
{
return (float)genrand_real2();
}
private float NextFloat(bool includeOne)
{
if (includeOne)
{
return (float)genrand_real1();
}
return (float)genrand_real2();
}
private float NextFloatPositive()
{
return (float)genrand_real3();
}
private double NextDouble()
{
return genrand_real2();
}
private double NextDouble(bool includeOne)
{
if (includeOne)
{
return genrand_real1();
}
return genrand_real2();
}
private double NextDoublePositive()
{
return genrand_real3();
}
private double Next53BitRes()
{
return genrand_res53();
}
///
/// 使用当前时间的毫秒数初始化随机数生成器。
///
public void Initialize()
{
init_genrand((uint)DateTime.UtcNow.Millisecond);
}
///
/// 使用指定的种子初始化随机数生成器。
///
/// 用于初始化的种子。
public void Initialize(int seed)
{
init_genrand((uint)seed);
}
///
/// 使用指定的初始化数组初始化随机数生成器。
///
/// 初始化数组。
public void Initialize(int[] init)
{
var initArray = new uint[init.Length];
for (var i = 0; i < init.Length; ++i)
{
initArray[i] = (uint)init[i];
}
init_by_array(initArray, (uint)initArray.Length);
}
private void init_genrand(uint s)
{
mt[0] = s & 0xffffffffU;
for (mti = 1; mti < N; mti++)
{
mt[mti] = (uint)(1812433253U * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
mt[mti] &= 0xffffffffU;
}
}
private void init_by_array(uint[] init_key, uint key_length)
{
int i, j, k;
init_genrand(19650218U);
i = 1;
j = 0;
k = (int)(N > key_length ? N : key_length);
for (; k > 0; k--)
{
mt[i] = (uint)((mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525U)) + init_key[j] + j);
mt[i] &= 0xffffffffU;
i++;
j++;
if (i >= N)
{
mt[0] = mt[N - 1];
i = 1;
}
if (j >= key_length)
{
j = 0;
}
}
for (k = N - 1; k > 0; k--)
{
mt[i] = (uint)((mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) *
1566083941U)) - i);
mt[i] &= 0xffffffffU;
i++;
if (i >= N)
{
mt[0] = mt[N - 1];
i = 1;
}
}
mt[0] = 0x80000000U;
}
private uint genrand_int32()
{
uint y;
if (mti >= N)
{
int kk;
if (mti == N + 1)
{
init_genrand(5489U);
}
for (kk = 0; kk < N - M; kk++)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1U];
}
for (; kk < N - 1; kk++)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U];
}
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1U];
mti = 0;
}
y = mt[mti++];
y ^= y >> 11;
y ^= (y << 7) & 0x9d2c5680U;
y ^= (y << 15) & 0xefc60000U;
y ^= y >> 18;
return y;
}
private int genrand_int31()
{
return (int)(genrand_int32() >> 1);
}
private FP genrand_FP()
{
return genrand_int32() * (FP.One / 4294967295);
}
private double genrand_real1()
{
return genrand_int32() * (1.0 / 4294967295.0);
}
private double genrand_real2()
{
return genrand_int32() * (1.0 / 4294967296.0);
}
private double genrand_real3()
{
return (genrand_int32() + 0.5) * (1.0 / 4294967296.0);
}
private double genrand_res53()
{
uint a = genrand_int32() >> 5, b = genrand_int32() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
}