如何用8位字节高效打包三进制数

How to pack ternary numbers in 8-bit bytes

9JoshTriplett💬 6
如何用8位字节高效打包三进制数

最近我被BitNet b1.58的三进制权重打包问题彻底吸引了。目标是让每个三进制位(trit)尽可能接近理论极限的1.58位存储空间。经过一番计算,我发现5个trit刚好能紧凑地塞进8位字节,效率高达99.06%。更妙的是,我找到了一种利用定点数乘法来替代传统取模运算的技巧,这让SIMD并行解包变得异常高效。这套方案不仅逻辑严密,而且已经成功应用在llama.cpp中,支持AVX2和ARM NEON指令集,为LLM权重的存储与加载提供了全新的优化思路。

"将8位字节乘以3,就能轻松从结果的高两位提取出数字,这比在SIMD环境下使用取模运算方便得多。"

HN 评论区

  • 有评论者指出,对于 CPU 而言,使用 768 字节的查找表(lookup table)通常比复杂的位运算打包方案更快,因为它能完全放入 L1 缓存并一次性提取 3 个 trits。
  • 一位从业者提到,该三进制打包技术已被 llama.cpp 用于运行 BitNet b1.58 等模型,其权重存储为 {-1, 0, 1} 的 ternary 类型,旨在显著降低延迟、内存和能耗。
  • JoshTriplett 分析认为,虽然 5 个 trits 打包进 8 字节的效率已接近最优,但要进一步突破理论极限,需要处理如 111 个 trits 打包进 176 位这样的大批量数据,且节省的存储空间在 27B 参数规模下仅为 38-45MB。
  • 有观点反驳了将 null 视为“十亿美元错误”的看法,认为 null 仅表示“无数据”,缺乏明确区分“肯定有数据”和“可能有数据”的类型系统(如 Java 中的 Foo 与 Option<Foo>)才是真正的问题所在。
  • 一位开发者分享经验称,为了适配 SIMD 指令集,该方案采用定点数(fixed point)而非浮点数,通过预计算倒数将除法转换为乘法,仅使用乘法、位移和按位与操作即可高效提取最高位 trit。

同日更多故事 · 2026-07-21