metrale_cache/kv_dequant/
luts.rs1pub const NVFP4_GROUP_SIZE: usize = 16;
13
14pub const NVFP4_E2M1_LUT: [f32; 16] = [
17 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, -0.0, -0.5, -1.0, -1.5, -2.0, -3.0, -4.0, -6.0,
18];
19
20pub const TURBO4_LUT: [f32; 16] = [
23 -2.7326, -2.0690, -1.6180, -1.2562, -0.9423, -0.6568, -0.3880, -0.1284, 0.1284, 0.3880, 0.6568,
24 0.9423, 1.2562, 1.6180, 2.0690, 2.7326,
25];
26
27pub const TURBO3_LUT: [f32; 8] = [
30 -2.1520, -1.3440, -0.7560, -0.2451, 0.2451, 0.7560, 1.3440, 2.1520,
31];
32
33const E4M3_LUT: [f32; 256] = {
36 let mut lut = [0.0f32; 256];
37 let mut byte = 0u32;
38 while byte < 256 {
39 let sign_bit = (byte >> 7) & 1;
40 let exp = ((byte >> 3) & 0xF) as i32;
41 let mant = byte & 0x7;
42 let s: f32 = if sign_bit == 0 { 1.0 } else { -1.0 };
43 lut[byte as usize] = if exp == 0 {
44 if mant == 0 {
45 s * 0.0
46 } else {
47 s * (mant as f32) * exp2(-9)
48 }
49 } else if exp == 0xF && mant == 0x7 {
50 f32::NAN
51 } else {
52 s * exp2(exp - 7) * (1.0 + (mant as f32) / 8.0)
53 };
54 byte += 1;
55 }
56 lut
57};
58
59const fn exp2(e: i32) -> f32 {
63 let mut v = 1.0f32;
64 let mut i = 0i32;
65 if e >= 0 {
66 while i < e {
67 v *= 2.0;
68 i += 1;
69 }
70 } else {
71 while i < -e {
72 v /= 2.0;
73 i += 1;
74 }
75 }
76 v
77}
78
79pub fn e4m3_lut() -> &'static [f32; 256] {
81 &E4M3_LUT
82}
83
84#[cfg(test)]
85mod lut_tests {
86 use super::*;
87
88 #[test]
91 fn the_const_table_is_bit_identical_to_the_powi_formula() {
92 for byte in 0..256u32 {
93 let sign_bit = (byte >> 7) & 1;
94 let exp = ((byte >> 3) & 0xF) as i32;
95 let mant = byte & 0x7;
96 let s: f32 = if sign_bit == 0 { 1.0 } else { -1.0 };
97 let expected: f32 = if exp == 0 {
98 if mant == 0 {
99 s * 0.0
100 } else {
101 s * (mant as f32) * 2.0f32.powi(-9)
102 }
103 } else if exp == 0xF && mant == 0x7 {
104 f32::NAN
105 } else {
106 s * 2.0f32.powi(exp - 7) * (1.0 + (mant as f32) / 8.0)
107 };
108 let got = E4M3_LUT[byte as usize];
109 if expected.is_nan() {
110 assert!(got.is_nan(), "byte {byte}: expected NaN, got {got}");
111 } else {
112 assert_eq!(
113 got.to_bits(),
114 expected.to_bits(),
115 "byte {byte}: {got} != {expected}"
116 );
117 }
118 }
119 }
120
121 #[test]
122 fn exp2_matches_powi_across_the_domain() {
123 for e in -9..=8i32 {
124 assert_eq!(exp2(e).to_bits(), 2.0f32.powi(e).to_bits(), "2^{e}");
125 }
126 }
127}