feat(numeric): add basic random number generator function
This commit is contained in:
parent
2d06667c40
commit
9d901df68a
51
Redcraft.Utility/Source/Private/Numeric/Random.cpp
Normal file
51
Redcraft.Utility/Source/Private/Numeric/Random.cpp
Normal 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
|
@ -6,3 +6,4 @@
|
|||||||
#include "Numeric/Numbers.h"
|
#include "Numeric/Numbers.h"
|
||||||
#include "Numeric/Bit.h"
|
#include "Numeric/Bit.h"
|
||||||
#include "Numeric/Math.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
|
Loading…
Reference in New Issue
Block a user