Skip to content

feat: BFloat16 Support#1127

Merged
kavirajk merged 11 commits intomainfrom
kavirajk/bfloat16-support
Jan 22, 2026
Merged

feat: BFloat16 Support#1127
kavirajk merged 11 commits intomainfrom
kavirajk/bfloat16-support

Conversation

@kavirajk
Copy link
Contributor

Summary

Internally we use uint16 to store 16-bit value of BFloat16
but we use float32 in the external APIs for the easy of use.

The complex part was how to round of Float32 -> Float16 without any systematic bias. Using banker's bias algorithm (closes-to-even bias)

Checklist

Delete items not relevant to your PR:

  • Unit and integration tests covering the common scenarios were added
  • A human-readable description of the changes was provided to include in CHANGELOG
  • For significant changes, documentation in https://github.com/ClickHouse/clickhouse-docs was updated with further explanations or tutorials

@kavirajk kavirajk requested a review from chernser as a code owner January 20, 2026 13:02
@kavirajk kavirajk requested a review from ernado January 20, 2026 13:03
@kavirajk kavirajk force-pushed the kavirajk/bfloat16-support branch 2 times, most recently from ed0f3b2 to 04719c0 Compare January 21, 2026 09:36
Internally we use uint16 to store 16-bit value of BFloat16
but use float32 in the external APIs for the easy of use.

Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
@kavirajk kavirajk force-pushed the kavirajk/bfloat16-support branch from 90be89f to 6aea98f Compare January 21, 2026 10:22
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Dynamic random source based on timestamp keep changing the "golden" test
file causing it to fail.

Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>

func (c ColBFloat16) Row(i int) float32 {
// BFloat16 is upper 16 bits of float32
bits := uint32(c[i]) << 16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do ClickHouse BFloat16 has a sign bit? So may be only 15 bits shift?

btw, here is a library that may be useful https://github.com/chenxingqiang/go-floatx/blob/master/float16.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. BFloat16 has the signed bit. Hence we use only the "upper" 16 bits (that always include signed bit)

I verified with inserting some negative values for BFloat16 CH

 INSERT INTO bfloat_test VALUES (1, 1.3);
INSERT INTO bfloat_test VALUES (1, -1.8);
SELECT *
FROM bfloat_test

Query id: 79f16ef4-f53b-498f-a619-46b791f153db

   ┌─id─┬───────val─┐
1. │  1 │ -1.796875 │
2. │  1 │  1.296875 │
   └────┴───────────┘

expected float32
delta float64
}{
{"zero", 0.0, 0.0, 0.0},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this library https://github.com/chenxingqiang/go-floatx claims to test all possible values. May be take same approach? =)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. We should definitely do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.
46d982f

@SpencerTorres
Copy link
Member

Awesome PR! Quick question: does the algorithm you mention prevent any differences that may come up in memory due to CPU architecture/instructions? I want to make sure we don't see any differences in the data when receiving/sending it, or when converting from float to int. Expanded tests, perhaps even on different archs could be needed. I see our CI has amd64 and 386, but does this cover ARM? We did have an issue in the past with overflows on some CPUs for clickhouse-go

Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
@kavirajk
Copy link
Contributor Author

but does this cover ARM? We did have an issue in the past with overflows on some CPUs for clickhouse-go

Good point @SpencerTorres. It make sense to extend CI testing to ARM. Added it in our workflows

Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
@kavirajk
Copy link
Contributor Author

Ok. I see the reason why ARM64 was not added before. Basically ARM runners are not cheap and not readily available in Github.

I enabled it and it just waiting for more than 20 mins just to get the runner. even then it got timed out.

[run (oldstable, v21.8.14.5-lts, ubuntu-latest-arm64)](https://github.com/ClickHouse/ch-go/actions/runs/21245385769/job/61133599215?pr=1127#logs)
Started 13m 1s ago
Evaluating run.if
Evaluating: success()
Result: true
Requested labels: ubuntu-latest-arm64
Job defined at: ClickHouse/ch-go/.github/workflows/e2e.yml@refs/pull/1127/merge
Waiting for a runner to pick up this job...

I'm going to remove the ARM64 for now. We can tackle this in separate PR (need different enterprise plan to get ARM64 runners)

@SpencerTorres

Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
Signed-off-by: Kaviraj <kavirajkanagaraj@gmail.com>
@kavirajk
Copy link
Contributor Author

@SpencerTorres created new issue to add ARM64 based github runners for the CI.
#1128

@kavirajk kavirajk merged commit 93467b5 into main Jan 22, 2026
19 checks passed
@kavirajk kavirajk deleted the kavirajk/bfloat16-support branch January 22, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants