| 66 | } |
| 67 | |
| 68 | func TestBFloat16_Rounding(t *testing.T) { |
| 69 | // BFloat16 has 7 bits of mantissa. For 1.0, ULP is 2^-7, and half ULP is 2^-8. |
| 70 | // Values are rounded to nearest even. 1.0 + 2^-8 should round to 1.0 (even mantissa). |
| 71 | |
| 72 | // The float32 representation of 1.0 is 0x3F800000. |
| 73 | // Adding 2^-8 (1/256) means setting bit 15 (23-8). |
| 74 | // So, 1.0 + 2^-8 in float32 is 0x3F808000. |
| 75 | val1 := math.Float32frombits(0x3F808000) // 1.0 + 2^-8 |
| 76 | bf1 := bfloat16.BFloat16FromFloat32(val1) |
| 77 | assert.Equal(t, uint16(0x3F80), bf1.Bits(), "Round to even (down)") |
| 78 | |
| 79 | // For 1.0 + 3 * 2^-8 (1.5 ULP), bits 15 and 14 are set, |
| 80 | // making the float32 representation 0x3F80C000. This rounds up. |
| 81 | val2 := math.Float32frombits(0x3F80C000) |
| 82 | bf2 := bfloat16.BFloat16FromFloat32(val2) |
| 83 | assert.Equal(t, uint16(0x3F81), bf2.Bits(), "Round up") |
| 84 | |
| 85 | // 1.0 + 2^-7 is the next representable number after 1.0. In float32, this is 0x3F810000. |
| 86 | val3 := math.Float32frombits(0x3F810000) |
| 87 | bf3 := bfloat16.BFloat16FromFloat32(val3) |
| 88 | assert.Equal(t, uint16(0x3F81), bf3.Bits(), "Exact") |
| 89 | |
| 90 | // For 1.0 + 2^-7 + 2^-8 (0x3F818000), the LSB (bit 16) of 0x3F81 is 1 (odd), |
| 91 | // and the guard bit (bit 15) is 1. Rounding to nearest even means rounding up. |
| 92 | // Result: 0x3F82. |
| 93 | val4 := math.Float32frombits(0x3F818000) |
| 94 | bf4 := bfloat16.BFloat16FromFloat32(val4) |
| 95 | assert.Equal(t, uint16(0x3F82), bf4.Bits(), "Round to even (up)") |
| 96 | } |