模擬設備多狀態行為:每種狀態出現概率不同(如 12%、40%、40%、7%、1%)。需一個隨機生成器,按配置概率分布返回狀態值,用於 5000 萬條記錄、20 萬設備的高併發壓測場景。
double percent[](不要求和為 100,內部自動歸一化)。rand() % 10000 命中槽位,直接返回對應狀態。優勢:O(1) 查詢、無鎖並行安全(構建後只讀)、分布精確、無條件分支預測失敗。
#define MAX_TOKENS 100
#define TABLE_SIZE 10000
class CTonyRandomArea {
public:
// pPercent: 概率數組;count: 有效類型數
CTonyRandomArea(double *pPercent, char count) {
m_count = (count > MAX_TOKENS) ? MAX_TOKENS : count;
// 1. 複製並歸一化百分比
double sum = 0;
for (int i = 0; i < m_count; ++i) {
m_percent[i] = pPercent[i];
sum += m_percent[i];
}
if (fabs(sum - 100.0) > 1e-9) { // 非 100 自動歸一化
for (int i = 0; i < m_count; ++i)
m_percent[i] = m_percent[i] / sum * 100.0;
}
// 2. 轉換為整數槽位數(0.01% 精度)
for (int i = 0; i < m_count; ++i)
m_slots[i] = (short)(m_percent[i] * 100); // 10000 * 1% = 100
// 3. 填充查表數組
int pos = 0;
for (int i = 0; i < m_count; ++i) {
int end = pos + m_slots[i];
for (int j = pos; j < end; ++j)
m_table[j] = (char)i;
pos = end;
}
// 兜底:浮點誤差導致 pos < 10000 時填最後一類
for (int j = pos; j < TABLE_SIZE; ++j)
m_table[j] = m_count - 1;
}
// 核心 API:按概率返回隨機類型
char GetRandomType() {
return m_table[GetRandomBetween(0, TABLE_SIZE)];
}
// 可選:指定索引查表(測試/調試用)
char GetType(int idx) {
if (idx < 0) idx = 0;
if (idx >= TABLE_SIZE) idx = TABLE_SIZE - 1;
return m_table[idx];
}
void PrintfInfo() { /* 打印內部分布驗證 */ }
private:
double m_percent[MAX_TOKENS];
short m_slots[MAX_TOKENS];
char m_table[TABLE_SIZE];
char m_count;
};
// 跨平台隨機數工具(避免 rand() 返回 0)
inline int GetRandomBetween(int min, int max) {
if (min > max) { int t = min; min = max; max = t; }
if (min == max) max = min + 10;
int range = max - min;
int r = rand(); if (r == 0) r = 1; // 簡單處理
return min + (r % range);
}
void TestCTonyRandomArea() {
double p[5] = {12.0, 40.0, 40.0, 7.0, 1.0};
CTonyRandomArea gen(p, 5);
gen.PrintfInfo();
for (int i = 0; i < 20; ++i)
printf("RandType = %d\n", gen.GetRandomType());
}
| 特性 | 實現細節 |
|---|---|
| 自動歸一化 | 輸入原始計數或百分比均可,構造函數內部處理 |
| 精度控制 | 10000 槽位 = 0.01% 精度,滿足工業級需求 |
| 無鎖並行 | 構造後 m_table 只讀,多線程直接調用 GetRandomType 無需鎖(符合《0bug》P50「用鎖最高境界——不用」) |
| API 分層 | GetRandomType(高層)、GetType(中層查表)、GetRandomBetween(底層隨機),調用者按需選擇 |
| 防禦性編程 | 索引越界鉗制、rand()==0 修正、參數順序自動交換 |
Normalize()、BuildTable() 私有方法。if (sum != 100.0) 風險極大,已修正為 fabs(sum-100) > 1e-9。srand((unsigned)time(nullptr)),勿重複調用。m_table[10000] 為成員變量(堆/數據段),非棟上分配,安全。本文出自 “肖舸的blog”,原文地址:https://tonyxiaohome.blog.51cto.com/925273/296530