| 26 | ) |
| 27 | |
| 28 | func TestBFloat16_Conversion(t *testing.T) { |
| 29 | tests := []struct { |
| 30 | name string |
| 31 | f32 float32 |
| 32 | want uint16 // bits |
| 33 | check bool // if true, check exact bits |
| 34 | }{ |
| 35 | {"Zero", 0.0, 0x0000, true}, |
| 36 | {"NegZero", float32(math.Copysign(0, -1)), 0x8000, true}, |
| 37 | {"One", 1.0, 0x3F80, true}, |
| 38 | {"MinusOne", -1.0, 0xBF80, true}, |
| 39 | {"Inf", float32(math.Inf(1)), 0x7F80, true}, |
| 40 | {"NegInf", float32(math.Inf(-1)), 0xFF80, true}, |
| 41 | // 1.5 -> 0x3FC0. (0x3FC00000 is 1.5) |
| 42 | {"OnePointFive", 1.5, 0x3FC0, true}, |
| 43 | } |
| 44 | |
| 45 | for _, tt := range tests { |
| 46 | t.Run(tt.name, func(t *testing.T) { |
| 47 | bf16 := bfloat16.BFloat16FromFloat32(tt.f32) |
| 48 | if tt.check { |
| 49 | assert.Equal(t, tt.want, bf16.Bits(), "Bits match") |
| 50 | } |
| 51 | |
| 52 | // Round trip check |
| 53 | roundTrip := bf16.Float32() |
| 54 | if math.IsInf(float64(tt.f32), 0) { |
| 55 | assert.True(t, math.IsInf(float64(roundTrip), 0)) |
| 56 | assert.Equal(t, math.Signbit(float64(tt.f32)), math.Signbit(float64(roundTrip))) |
| 57 | } else if math.IsNaN(float64(tt.f32)) { |
| 58 | assert.True(t, math.IsNaN(float64(roundTrip))) |
| 59 | } else { |
| 60 | if tt.check { |
| 61 | assert.Equal(t, tt.f32, roundTrip, "Round trip value match") |
| 62 | } |
| 63 | } |
| 64 | }) |
| 65 | } |
| 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. |