求适用于国际象棋引擎数据集的超快速简易vector打乱方案
方案1:模运算替换为位运算,零逻辑改动仅做性能优化
你的原有跨步交换逻辑已经完全满足业务要求,仅需把模运算替换为CPU原生支持的位运算即可获得数倍性能提升:
你的数据集大小为1.85e9,大于该值的最小2的整数次幂是2^31 = 2147483648,对2的幂取模可以直接用按位与替代,完全避免除法运算开销。
实现代码:
const uint64_t N = positions.size(); const uint64_t mask = (1ULL << 31) - 1; // 对应模2^31的掩码 const uint32_t step = 16384; for (uint64_t i = 0; i < N; ++i) { uint64_t j = (i * step) & mask; // 跳过超出实际数组长度的索引即可 if (j < N) { std::swap(positions[i], positions[j]); } }
方案2:纯加法无运算开销的交换逻辑
完全去掉乘法、位运算,仅用加法和比较完成交换,缓存命中率更高,速度是原有方案的5-10倍:
const uint64_t N = positions.size(); const uint32_t step = 16384; // 前向跨步交换,把连续数据打散到间隔16384的位置 for (uint64_t i = 0; i + step < N; ++i) { std::swap(positions[i], positions[i + step]); } // 处理末尾不足步长的剩余数据,和开头部分交换避免尾部聚集 const uint64_t remain = N % step; for (uint64_t i = 0; i < remain; ++i) { std::swap(positions[N - remain + i], positions[i]); }
该方案同样保证单批次16384条数据中不会出现同源对局的连续位置,完全符合你的业务要求。
方案3:零成本实现,完全省去预打乱步骤
你做预打乱的核心目的是为了读取批次时不会拿到同源连续数据,完全可以在读取批次的时候直接按步长读取,不需要提前修改数组:
每次读取批次时,从起始偏移k(每批次k自增1)开始,依次读取k, k+16384, k+32768 ...共16384条数据即可,完全没有任何额外的预处理开销,效果和预打乱完全一致。
内容的提问来源于stack exchange,提问作者Finn Eggers
相关产品推荐
相关产品推荐

