Redcraft/Redcraft.Utility/Source/Public/Numerics/Random.h

89 lines
2.0 KiB
C++

#pragma once
#include "CoreTypes.h"
#include "Numerics/Bit.h"
#include "Numerics/Math.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Math)
/** Seeds the random number generator. Return the previous seed. */
NODISCARD REDCRAFTUTILITY_API uint32 Seed(uint32 InSeed = 0);
/** @return The generated random number within the range of [0, 0x7FFFFFFF). */
NODISCARD REDCRAFTUTILITY_API uint32 Rand();
/** @return The generated random number within the range of [0, A). */
template <CIntegral T>
NODISCARD FORCEINLINE T Rand(T A)
{
constexpr uint32 RandStateNum = 0x7FFFFFFF;
if (A <= 0) return 0;
if (A <= RandStateNum) return Rand() % A;
constexpr uint32 BlockSize = Math::BitFloor(RandStateNum);
constexpr uint BlockWidth = Math::CountRightZero(BlockSize);
const T BlockNum = Math::DivAndCeil(A, BlockSize);
T Result = 0;
for (T I = 0; I < BlockNum; ++I)
{
Result ^= Rand();
Result <<= BlockWidth;
}
return Math::Abs(Result) % A;
}
/** @return The generated random number within the range of [0, A). */
template <CFloatingPoint T>
NODISCARD FORCEINLINE T Rand(T A)
{
constexpr uint32 RandStateNum = 0x7FFFFFFF;
if (Math::IsNegative(A)) return TNumericLimits<T>::QuietNaN();
constexpr size_t BlockNum = Math::DivAndCeil(sizeof(T), 4);
T Multiplier = A;
Multiplier /= BlockNum;
Multiplier /= RandStateNum;
T Result = 0;
for (size_t I = 0; I < BlockNum; ++I)
{
Result += Rand() * Multiplier;
}
return Result;
}
/** @return The generated random number within the range of [A, B). */
template <CArithmetic T, CArithmetic U> requires (CCommonType<T, U>)
NODISCARD FORCEINLINE auto RandWithin(T A, U B)
{
using FCommonT = TCommonType<T, U>;
if (A == B) return static_cast<FCommonT>(A);
if (A > B) return Math::RandWithin(B, A);
return static_cast<FCommonT>(A + Math::Rand(B - A));
}
NAMESPACE_END(Math)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END