| |
| |
|
|
| export function f16ToF32(u16) { |
| const sign = u16 & 0x8000 ? -1 : 1; |
| const exp = (u16 >> 10) & 0x1f; |
| const mant = u16 & 0x3ff; |
| if (exp === 0) return sign * mant * 2 ** -24; |
| if (exp === 31) return mant ? NaN : sign * Infinity; |
| return sign * (1024 + mant) * 2 ** (exp - 25); |
| } |
|
|
| |
| |
| const f32View = new Float32Array(1); |
| const u32View = new Uint32Array(f32View.buffer); |
|
|
| export function f32ToF16(value) { |
| f32View[0] = value; |
| const x = u32View[0]; |
| const sign = (x >>> 16) & 0x8000; |
| const exp = (x >>> 23) & 0xff; |
| let mant = x & 0x7fffff; |
| if (exp === 0xff) return sign | 0x7c00 | (mant ? 0x200 : 0); |
| const e = exp - 127 + 15; |
| if (e >= 0x1f) return sign | 0x7c00; |
| if (e <= 0) { |
| if (e < -10) return sign; |
| mant |= 0x800000; |
| const shift = 14 - e; |
| const half = mant >> shift; |
| const rem = mant & ((1 << shift) - 1); |
| const halfway = 1 << (shift - 1); |
| if (rem > halfway || (rem === halfway && (half & 1))) return sign | (half + 1); |
| return sign | half; |
| } |
| const half = (e << 10) | (mant >> 13); |
| const rem = mant & 0x1fff; |
| if (rem > 0x1000 || (rem === 0x1000 && (half & 1))) return sign | (half + 1); |
| return sign | half; |
| } |
|
|
| export function expandF16(src) { |
| const n = src.length; |
| const out = new Float32Array(n); |
| for (let i = 0; i < n; i++) { |
| const u16 = src[i]; |
| const exp = (u16 >> 10) & 0x1f; |
| const mant = u16 & 0x3ff; |
| const sign = u16 & 0x8000 ? -1 : 1; |
| if (exp === 0) out[i] = sign * mant * 2 ** -24; |
| else if (exp === 31) out[i] = mant ? NaN : sign * Infinity; |
| else out[i] = sign * (1024 + mant) * 2 ** (exp - 25); |
| } |
| return out; |
| } |
|
|