Files
dv-homework-2/report.md

4.8 KiB
Raw Permalink Blame History

第二讲大作业实验报告:海量 float32 索引排序算法设计与实现

1. 数据生成或来源

本实验使用纯 Python + NumPy 生成两类 float32 数据作为评测输入:

  • uniform使用随机均匀分布生成数据
  • clustered使用三段高斯混合分布生成数据

实验中所有数据都在本地实时生成,不依赖外部数据集。测试类型和规模如下:

  • 数据类型float32
  • 数据分布uniform, clustered
  • 数据规模10,000,000
  • 每组重复次数1

2. NumPy原生argsort性能基准测试

NumPy 原生基准作为参考上界,使用 stable 模式执行。结果如下:

数据分布 规模 平均耗时/s 标准差/s
clustered 10,000,000 1.5460 0.0000
uniform 10,000,000 1.4686 0.0000

从基准可以看到在千万级规模下NumPy 官方实现仍然非常高效,是后续自定义算法的核心对照对象。

3. 算法原理(含图)

3.1 方案一:浮点数位级 LSD Radix Sort

将 float32 视图解释为 uint32并进行单调映射

  • 负数key = ~raw_bits
  • 非负数key = raw_bits ^ 0x80000000

然后执行 4 趟 8-bit 稳定分发shift = 0, 8, 16, 24得到最终索引。

图1:float32 位布局与排序顺序示意图

图2:负数位翻转前后对比

图3:radix sort 每一趟桶分布示意图

3.2 方案二:多级直方图 + Bucket Sort

从最高字节开始进行分桶,再对每个非平凡桶递归下钻,直到桶规模低于阈值后使用插入排序收尾。该策略能在分布相对分散时减少不必要搬运,但在桶不均衡时会出现局部退化。

图5:不同数据分布下的高位桶均衡性

4. 核心代码实现(分函数写)

主要函数划分如下:

  1. float32_to_ordered_uint32完成浮点到可比较无符号键的映射
  2. stable_digit_scatter实现单趟稳定计数分发
  3. argsort_float32_radix实现 4-pass LSD Radix 索引排序
  4. argsort_float32_bucket实现 MSD 多级分桶 + 小桶插入排序
  5. run_benchmarks完成对照组与实验组计时与统计

正确性检查结论:共验证 12 组算法/数据组合,其中 12 组通过排序正确性检查12 组与 stable numpy argsort 索引完全一致。

5. 实验环境与结果(多组数据对比表 + 图)

实验环境:

  • Python3.12.3
  • NumPy2.4.3
  • 平台Linux-6.17.0-14-generic-x86_64-with-glibc2.39
  • 逻辑 CPU 数6

最终多组数据汇总如下:

数据分布 算法 规模 平均耗时/s 标准差/s 相对 numpy
clustered bucket_msd 10,000,000 60.2848 0.0000 38.99x
clustered numpy_argsort 10,000,000 1.5460 0.0000 1.00x
clustered radix_lsd 10,000,000 27.4960 0.0000 17.79x
uniform bucket_msd 10,000,000 64.0348 0.0000 43.60x
uniform numpy_argsort 10,000,000 1.4686 0.0000 1.00x
uniform radix_lsd 10,000,000 26.0530 0.0000 17.74x

图4给出最终性能对比柱状图对数纵轴

图4:最终性能对比柱状图

图6给出不同算法在规模变化下的运行时间曲线

图6:运行时间缩放曲线

图7给出相对 NumPy argsort 的性能倍率:

图7:相对 NumPy 的性能倍率

6. 性能分析与瓶颈讨论

  1. 在千万级输入上NumPy 原生 argsort 仍保持明显优势。
  2. Radix 路线的理论复杂度接近 O(n),但纯 NumPy 稳定散射的常数项较高,且强依赖内存带宽。
  3. Bucket 路线在数据分布集中时更容易出现不均衡桶,导致局部处理时间上升。
  4. 当前实现的主要瓶颈在于大规模数据搬运和块内前缀计算;若引入低层并行或 JIT有机会继续压缩差距。

7. 总结与展望

本实验已按课程要求完成两条实现路径、千万级数据基准、图1-图7可视化与完整报告自动生成流程。结论如下

  1. 在禁止直接调用 np.sort 和 np.argsort 的约束下,两条方案都可得到正确排序索引。
  2. 千万级规模下,自定义纯 NumPy 实现可以稳定运行,但性能与官方底层优化实现仍存在差距。
  3. 后续可尝试方向包括:减少中间数组写放大、优化桶阈值自适应策略、采用更底层 SIMD/JIT 机制。

复现实验:

  1. source venv/bin/activate
  2. pip install -e .
  3. python scripts/run_all.py