feat(numeric): add basic random number generator function
This commit is contained in:
@ -6,3 +6,4 @@
|
||||
#include "Numeric/Numbers.h"
|
||||
#include "Numeric/Bit.h"
|
||||
#include "Numeric/Math.h"
|
||||
#include "Numeric/Random.h"
|
||||
|
88
Redcraft.Utility/Source/Public/Numeric/Random.h
Normal file
88
Redcraft.Utility/Source/Public/Numeric/Random.h
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Numeric/Bit.h"
|
||||
#include "Numeric/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
|
Reference in New Issue
Block a user