feat(numeric): add basic random number generator function

This commit is contained in:
Redstone1024 2024-12-04 22:05:50 +08:00
parent 2d06667c40
commit 9d901df68a
3 changed files with 140 additions and 0 deletions

View File

@ -0,0 +1,51 @@
#include "Numeric/Random.h"
#include "Templates/Atomic.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
NAMESPACE_BEGIN(Math)
NAMESPACE_UNNAMED_BEGIN
TAtomic<uint32> RandState = 586103306;
NAMESPACE_UNNAMED_END
uint32 Seed(uint32 InSeed)
{
uint32 OldSeed = RandState.Load(EMemoryOrder::Relaxed);
if (InSeed != 0) RandState.Store(InSeed, EMemoryOrder::Relaxed);
return OldSeed;
}
uint32 Rand()
{
uint32 Result;
RandState.FetchFn(
[&Result](uint32 Value)
{
Result = Value;
Result ^= Result << 13;
Result ^= Result >> 17;
Result ^= Result << 5;
return Result;
},
EMemoryOrder::Relaxed
);
return Result % 0x7FFFFFFF;
}
NAMESPACE_END(Math)
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -6,3 +6,4 @@
#include "Numeric/Numbers.h"
#include "Numeric/Bit.h"
#include "Numeric/Math.h"
#include "Numeric/Random.h"

View 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