Float16FromFloat32 converts a float32 to a Float16. Rounds to nearest, ties to even.
(f32 float32)
| 66 | // Float16FromFloat32 converts a float32 to a Float16. |
| 67 | // Rounds to nearest, ties to even. |
| 68 | func Float16FromFloat32(f32 float32) Float16 { |
| 69 | bits := math.Float32bits(f32) |
| 70 | sign := (bits >> 31) & 0x1 |
| 71 | exp := (bits >> 23) & 0xff |
| 72 | mant := bits & 0x7fffff |
| 73 | |
| 74 | var outSign uint16 = uint16(sign) << 15 |
| 75 | var outExp uint16 |
| 76 | var outMant uint16 |
| 77 | |
| 78 | if exp == 0xff { |
| 79 | // NaN or Inf |
| 80 | outExp = 0x1f |
| 81 | if mant != 0 { |
| 82 | // NaN - preserve top bit of mantissa for quiet/signaling if possible, but simplest is canonical QNaN |
| 83 | outMant = 0x200 | (uint16(mant>>13) & 0x1ff) |
| 84 | if outMant == 0 { |
| 85 | outMant = 0x200 // Ensure at least one bit |
| 86 | } |
| 87 | } else { |
| 88 | // Inf |
| 89 | outMant = 0 |
| 90 | } |
| 91 | } else if exp == 0 { |
| 92 | // Signed zero or subnormal float32 (which becomes zero in float16 usually) |
| 93 | outExp = 0 |
| 94 | outMant = 0 |
| 95 | } else { |
| 96 | // Normalized |
| 97 | newExp := int(exp) - 127 + 15 |
| 98 | if newExp >= 31 { |
| 99 | // Overflow to Inf |
| 100 | outExp = 0x1f |
| 101 | outMant = 0 |
| 102 | } else if newExp <= 0 { |
| 103 | // Underflow to subnormal or zero |
| 104 | // Shift mantissa to align with float16 subnormal range |
| 105 | // float32 mantissa has implicit 1. |
| 106 | fullMant := mant | 0x800000 |
| 107 | shift := 1 - newExp // 1 for implicit bit alignment |
| 108 | // We need to round. |
| 109 | // Mantissa bits: 23. Subnormal 16 mant bits: 10. |
| 110 | // We want to shift right by (13 + shift). |
| 111 | |
| 112 | // Let's do a more precise soft-float rounding |
| 113 | // Re-assemble float value to handle subnormal rounding correctly is hard with just bit shifts |
| 114 | // But since we have hardware float32... |
| 115 | // Actually pure bit manipulation is robust if careful. |
| 116 | |
| 117 | // Shift right amount |
| 118 | netShift := 13 + shift // 23 - 10 + shift |
| 119 | |
| 120 | if netShift >= 24 { |
| 121 | // Too small, becomes zero |
| 122 | outExp = 0 |
| 123 | outMant = 0 |
| 124 | } else { |
| 125 | outExp = 0 |