Skip to content

Conversation

@sdcb
Copy link

@sdcb sdcb commented Dec 14, 2025

Fixes #122203

Copilot AI review requested due to automatic review settings December 14, 2025 09:33
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Dec 14, 2025
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 the UInt128 to double conversion for values >= 2^104. The issue was caused by incorrect handling of precision loss during the conversion, which has been corrected by implementing proper sticky bit rounding.

  • Fixed the rounding logic in the UInt128 to double explicit conversion operator
  • Added a regression test to verify the fix

Reviewed changes

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

File Description
src/libraries/System.Private.CoreLib/src/System/UInt128.cs Changed the conversion logic to use a sticky bit (1 if any of the lower 24 bits are set, 0 otherwise) instead of OR-ing the lower 24 bits directly, ensuring proper rounding for large values
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs Added a regression test that validates the conversion of a large UInt128 value (>= 2^104) to double produces the correct result

Copy link
Member

@huoyaoyuan huoyaoyuan left a comment

Choose a reason for hiding this comment

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

Can you please check if the issue is also present for Int128?

// lowest 24 bits and then or's them back to ensure rounding stays correct.

double lower = BitConverter.UInt64BitsToDouble(TwoPow76Bits | ((ulong)(value >> 12) >> 12) | (value._lower & 0xFFFFFF)) - TwoPow76;
double lower = BitConverter.UInt64BitsToDouble(TwoPow76Bits | ((ulong)(value >> 12) >> 12) | ((value._lower & 0xFFFFFF) != 0 ? 1UL : 0UL)) - TwoPow76;
Copy link
Member

Choose a reason for hiding this comment

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

Is it correcting the behavior for some case? If not, it's a deoptimization.

@sdcb
Copy link
Author

sdcb commented Dec 14, 2025

@dotnet-policy-service agree

@sdcb
Copy link
Author

sdcb commented Dec 14, 2025

Can you please check if the issue is also present for Int128?

Yes it's also present for Int128, also this fix also applies to Int128

sdcb added 3 commits December 15, 2025 17:18
- Correctly calculate the sticky bit when converting large UInt128 values (>= 2^104) to double to prevent precision loss.
- Optimize the upper bits extraction by accessing _upper directly instead of shifting.
- Add regression tests for Int128 to ensure it is also fixed.
- Update test comments to better explain the test cases.

Fixes dotnet#122203
@sdcb sdcb force-pushed the fix-uint128-conversion branch from c808380 to 5473f4b Compare December 15, 2025 09:18
Copy link
Member

@huoyaoyuan huoyaoyuan left a comment

Choose a reason for hiding this comment

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

The numbers can be constructed more intuitively (also Int128 ones)

Use decimal literals instead of scientific notation and hex constructors
instead of bit shifts for clearer test value representation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Numerics community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect (U)Int128 to double conversion

3 participants