Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

  • Analyze the issue: ILogB for Half and BFloat16 returns incorrect values for subnormal numbers because BitOperations.LeadingZeroCount only has overloads for uint/ulong/nuint, so the ushort from TrailingSignificand is implicitly widened to uint, adding 16 extra leading zeros
  • Fix Half.ILogB to use ushort.LeadingZeroCount which handles the bit-width adjustment
  • Fix BFloat16.ILogB to use byte.LeadingZeroCount after changing TrailingSignificand to return byte
  • Add tests to verify the fix for both Half.ILogB and BFloat16.ILogB with normal and subnormal values
  • Build and run tests to verify the fix (69,569 tests passed with 0 failures)

Security Summary

No security vulnerabilities were discovered or introduced by these changes.

Original prompt

This section details on the original issue you should resolve

<issue_title>Possibly incorrect implementation of ILogB for BFloat16 and Half</issue_title>
<issue_description>ILogB is implemented on Half as such:

return MinExponent - (BitOperations.LeadingZeroCount(x.TrailingSignificand) - BiasedExponentLength);

and TrailingSignificand is a ushort

internal ushort TrailingSignificand

However, BitOperations.LeadingZeroCount has no overload that accepts a ushort. So it is implicitly widened to the uint overload, and calculates the leading zero count as if the number had a 32-bit width instead of 16-bit.

I believe that means that Half.ILogB may be off by 16 for subnormal values (and probably BFloat16).

For example, for Half.Epsilon I would expect the ilogb to be -24, but is reported as -40.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

BitOperations.LeadingZeroCount has no ushort overload, so the
TrailingSignificand is implicitly widened to uint, adding 16 extra
leading zeros. Subtract 16 to correct for this widening.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix possibly incorrect implementation of ILogB for BFloat16 and Half Fix ILogB for Half and BFloat16 subnormal values Jan 17, 2026
Copilot AI requested a review from stephentoub January 17, 2026 00:25
…byte

Instead of adjusting the value at the call site, add internal overloads
of BitOperations.LeadingZeroCount for ushort and byte types that handle
the widening adjustment internally.

Update UInt16, Int16, Char, Byte, and SByte LeadingZeroCount methods to
use these new internal overloads.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
@stephentoub stephentoub marked this pull request as ready for review January 17, 2026 21:42
Copilot AI review requested due to automatic review settings January 17, 2026 21:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug in ILogB for Half and BFloat16 where subnormal values returned incorrect results due to implicit type widening. When BitOperations.LeadingZeroCount was called with a ushort argument (the type of TrailingSignificand), it was implicitly widened to uint, adding 16 extra leading zeros to the count.

Changes:

  • Added internal LeadingZeroCount overloads for ushort and byte in BitOperations that handle the bit-width adjustment
  • Refactored LeadingZeroCount in UInt16, Int16, Byte, SByte, and Char to use the new internal overloads, removing redundant manual adjustments
  • Added comprehensive tests for ILogB covering normal, special, and subnormal values for both Half and BFloat16

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
BitOperations.cs Adds internal LeadingZeroCount overloads for ushort and byte that correctly adjust for bit width when widening to uint
UInt16.cs Removes manual -16 adjustment, now uses internal LeadingZeroCount(ushort) overload
Int16.cs Removes manual -16 adjustment, now uses internal LeadingZeroCount(ushort) overload
Byte.cs Removes manual -24 adjustment, now uses internal LeadingZeroCount(byte) overload
SByte.cs Removes manual -24 adjustment, now uses internal LeadingZeroCount(byte) overload
Char.cs Removes manual -16 adjustment, now uses internal LeadingZeroCount(ushort) overload
HalfTests.cs Adds tests for ILogB including normal values, special values, and two subnormal test cases
BFloat16Tests.cs Adds tests for ILogB including normal values, special values, and two subnormal test cases

Per reviewer feedback, use the existing ushort.LeadingZeroCount method
which already handles the bit-width adjustment, instead of adding new
internal overloads to BitOperations.

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Merged latest changes from main and updated BFloat16.ILogB to use
ushort.LeadingZeroCount consistently with Half.ILogB, since
TrailingSignificand is ushort for both types.

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Undoes the previous merge commit that was not done correctly.

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
…ormula

- Changed TrailingSignificand property from ushort to byte
- Changed ExtractTrailingSignificandFromBits to return byte
- Changed MinTrailingSignificand and MaxTrailingSignificand constants to byte
- Updated IsPow2 to use byte.PopCount
- Updated ILogB to use byte.LeadingZeroCount with adjusted formula

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
@stephentoub stephentoub merged commit 0c56d0e into main Jan 20, 2026
148 checks passed
@stephentoub stephentoub deleted the copilot/fix-ilogb-implementation-half-bfloat16 branch January 20, 2026 03:01
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.

Possibly incorrect implementation of ILogB for BFloat16 and Half

3 participants