89 lines
2.0 KiB
C++
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
|