)
反量化Q8零.h// 反量化Q8零.h —— q8_0 量化块的反量化8 位量化无零偏移// 用途把 q8_0 块1 个 f16 缩放 32 个 int8 量化值转为 f32 输出。// 布局实测确认每块 32 元素、34 字节d(f16, 2B) q[32×int8, 32B]#pragmaonce// 引入基础类型浮点/索引#include公共/基础定义.h// 半精度转浮点把 IEEE-754 半精度16 位位模式转为单精度浮点// 说明GGUF 文件里的缩放是 IEEE-754 半精度1 符号位 5 指数位 10 尾数位// C 不保证有原生的 _Float16故用手动位操作实现见 .cpp 内详解浮点 半精度转浮点(uint16_t位);// 反量化Q8零块把一个 q8_0 量化块反量化为 f32// 参数块 量化数据起点34 字节输出 f32 输出缓冲区容量 ≥ 元素数元素数 32// 公式文档注释x_i q_i · d其中 q_i 是第 i 个 int8 量化值d 是块缩放void反量化Q8零块(constuint8_t*块,float*输出,size_t 元素数);反量化Q8零.cpp// 反量化Q8零.cpp —— q8_0 量化块的反量化实现// 用途把 q8_0 块1 个 f16 缩放 32 个 int8 量化值转为 f32 输出。// 布局d(f16, 2B) 32×int8 34 字节每块 32 元素x q·d#include内核/反量化/反量化Q8零.h// 半精度转浮点把 IEEE-754 半精度16 位位模式转为单精度浮点// IEEE-754 半精度布局1 符号位 | 5 指数位 | 10 尾数位// - 指数 0 且尾数 0±0// - 指数 0 且尾数 ≠ 0次正规数值 (-1)^符号 × 尾数 × 2^-24// - 指数 31 且尾数 0±∞// - 指数 31 且尾数 ≠ 0NaN非数// - 其余正规数值 (-1)^符号 × (1 尾数/1024) × 2^(指数-15)浮点 半精度转浮点(uint16_t位){// 符号位第 15 位const无符号 符号(位15)1;// 指数第 14~10 位const无符号 指数(位10)0x1F;// 尾数第 9~0 位const无符号 尾数位0x3FF;// 指数 0零或次正规数值 尾数 × 2^-24if(指数0){// 5.9604645e-8 2^-24单精度下的次正规最小步长return符号?-尾数*5.9604645e-8f:尾数*5.9604645e-8f;}// 指数 31无穷或 NaNif(指数31){if(尾数0){return符号?-std::numeric_limits浮点::infinity():std::numeric_limits浮点::infinity();}returnstd::numeric_limits浮点::quiet_NaN();}// 正规数(1 尾数/1024) × 2^(指数-15)符号另乘const浮点 值(1.0f尾数/1024.0f)*std::pow(2.0f,static_castint(指数)-15);return符号?-值:值;}// 反量化Q8零块把一个 q8_0 量化块反量化为 f32// 实现读前 2 字节为 f16 缩放 d小端随后 32 字节为 int8 量化值// 对每个元素 x_i q_i × dint8 先有符号扩展到 f32 再乘void反量化Q8零块(constuint8_t*块,float*输出,size_t 元素数){// 解析 f16 缩放小端两字节拼成 16 位模式constuint16_t缩放位static_castuint16_t(块[0]|(块[1]8));const浮点 d半精度转浮点(缩放位);// 逐个元素反量化q_iint8 有符号× dfor(size_t i0;i元素数;i){constint8_tqstatic_castint8_t(块[2i]);输出[i]static_cast浮点(q)*d;}}