Files
cKit/Foundation/c_Random.c
T
2026-08-30 22:24:45 +08:00

118 lines
3.8 KiB
C

#include <c_Random.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <unistd.h>
#endif
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
void c_Random_Init(void) {
// 1. 获取基础日历时间(秒级)
uint64_t seed_entropy = (uint64_t)time(NULL);
// 2. 获取高精度硬件/OS级时间戳,阻断高频重启或高并发时的秒级碰撞
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER perf_counter;
if (QueryPerformanceCounter(&perf_counter)) {
seed_entropy ^= (uint64_t)perf_counter.QuadPart;
} else {
seed_entropy ^= (uint64_t)GetTickCount();
}
// 混合当前进程 ID
seed_entropy ^= ((uint64_t)GetCurrentProcessId() << 16);
#else
struct timespec ts;
// 优先采用高精度纳秒单调时钟
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
seed_entropy ^= ((uint64_t)ts.tv_sec << 32) ^ (uint64_t)ts.tv_nsec;
} else if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
seed_entropy ^= ((uint64_t)ts.tv_sec << 32) ^ (uint64_t)ts.tv_nsec;
}
// 混合当前进程 ID
seed_entropy ^= ((uint64_t)getpid() << 16);
#endif
// 3. 核心避坑:加入运行时环境的 ASLR 栈空间地址作为环境噪声
// 局部变量在栈上的地址在每次运行时受操作系统 ASLR 影响都是随机的
volatile int dummy_stack_var = 0;
uintptr_t stack_address = (uintptr_t)&dummy_stack_var;
seed_entropy ^= (uint64_t)stack_address;
// 4. 将采集到的 64 位熵数据进行简单混淆(对折异或),降维匹配到标准库 srand 的参数空间
unsigned int final_seed = (unsigned int)(seed_entropy ^ (seed_entropy >> 32));
// 5. 播种
srand(final_seed);
}
/**
* @brief 生成指定闭区间 [min, max] 内的高质量均匀分布无符号整数
*
* @param min 区间下界(包含)
* @param max 区间上界(包含)
* @return uint64_t 生成的随机数
*/
uint64_t c_Random_RangeU64(uint64_t min, uint64_t max) {
if (min >= max) {
return min;
}
uint64_t range = max - min + 1;
// 核心:消除模数偏差 (Modulo Bias) 算法
// 计算在 RAND_MAX(或此处为 UINT64_MAX 映射区间)内排出的残缺余数窗口
uint64_t limit = UINT64_MAX - (UINT64_MAX % range);
uint64_t rand_val;
do {
// 拼接两个标准的 32 位随机数以组合成高质量的 64 位宽随机数源
// 若您的平台有硬件随机数(如 NDK 的 arc4random 或 x86 的 RDRAND),可在此处替换
uint64_t high = (uint32_t)rand();
uint64_t low = (uint32_t)rand();
rand_val = (high << 32) | low;
} while (rand_val >= limit); // 落在残缺窗口内的数直接丢弃,重新抽取
return min + (rand_val % range);
}
/**
* @brief 生成指定闭区间 [min, max] 内的高质量有符号整数
*/
int64_t c_Random_RangeI64(int64_t min, int64_t max) {
if (min >= max) return min;
// 将有符号区间平移映射至无符号空间处理,完美规避符号位溢出死锁
uint64_t range = (uint64_t)(max - min);
uint64_t limit = UINT64_MAX - (UINT64_MAX % (range + 1));
uint64_t rand_val;
do {
uint64_t high = (uint32_t)rand();
uint64_t low = (uint32_t)rand();
rand_val = (high << 32) | low;
} while (rand_val >= limit);
return min + (int64_t)(rand_val % (range + 1));
}
/**
* @brief 生成指定区间 [min, max) 内的双精度浮点数
*/
double c_Random_RangeDouble(double min, double max) {
if (min >= max) return min;
// 将标准生成的 64 位无符号随机数归一化映射到 [0.0, 1.0) 之间
double scale = (double)rand() / ((double)RAND_MAX + 1.0);
return min + scale * (max - min);
}