Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect tracking of sign bit #59525

Merged
merged 6 commits into from
Sep 28, 2021
Merged

Conversation

wzchua
Copy link
Contributor

@wzchua wzchua commented Sep 23, 2021

Fixes #59509

The detection was sufficient but the sign tracking should have be done within the 2's complement space.

The fix is now to set the last uint element to be 0xFFFFFFFF before converting the value back.
Also added an additional check to make sure this is only done for N x 32 bit right shifts

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Sep 23, 2021
@ghost
Copy link

ghost commented Sep 23, 2021

Tagging subscribers to this area: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #59509

I made an invalid assumption that it was impossible for the last uint to be 0 after the TwosComplement unless the uint was all max.

Now the logic explicitly checks that the inversion is all 0 with the first uint being 1

Author: wzchua
Assignees: -
Labels:

area-System.Numerics

Milestone: -

@@ -2021,9 +2021,22 @@ private static BigInteger Subtract(uint[]? leftBits, int leftSign, uint[]? right
}

NumericsHelpers.DangerousMakeTwosComplement(xd); // Mutates xd
if (xd[^1] == 0)

if (smallShift == 0 && xd[0] == 1)
Copy link
Member

Choose a reason for hiding this comment

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

It might just be that I'm not awake enough, but why aren't we simply doing trackSignBit = (_sign & int.MinValue) != 0?

That is, if the most significant bit of _sign is set, we are a signed value and therefore this is an arithmetic right shift and the sign bit needs to be propagated. Otherwise, its a logical (or effectively logical) right shift and it doesn't.

Copy link
Contributor Author

@wzchua wzchua Sep 23, 2021

Choose a reason for hiding this comment

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

We only need to track if it's the special sequence that #54115 was meant to fix
Cuz effectively for that sequence the sign bit is lost after the twoscomplement

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An alternative solution is we can expand the array by 1 element before performing 2's complement and normalize the uint array at the end

Copy link
Member

Choose a reason for hiding this comment

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

We only need to track if it's the special sequence that #54115 was meant to fix
Cuz effectively for that sequence the sign bit is lost after the twoscomplement

Ah, right. We don't store it directly as a negative value, we store the sign + magnitude, which makes this logic more complicated.

Copy link
Member

Choose a reason for hiding this comment

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

Can you add a code comment describing why this logic is needed for future readers. Otherwise this LGTM.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, i discovered a simpler fix. I should have set the last uint as 0xFFFFFFFF before the 2's complement

Copy link
Member

@tannergooding tannergooding left a comment

Choose a reason for hiding this comment

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

This looks correct to me.

I'm looking at what can be done to simplify this logic overall so we can avoid some of these issues in the future. I don't think having BigInteger store things as sign + magnitude is intuitive and it doesn't work well with the "natural" way to work with these types (nor many of the perf oriented algorithms for fast multiplication/division, etc).

@tannergooding
Copy link
Member

CC. @pgovind could you give this a secondary review.

trackSignBit = true;
}

// For a shift of N x 32 bit,
Copy link

Choose a reason for hiding this comment

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

Ah, helpful explanation.

Copy link

@pgovind pgovind left a comment

Choose a reason for hiding this comment

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

LGTM! Nice work!

@pgovind pgovind merged commit 7a58bef into dotnet:main Sep 28, 2021
@slozier
Copy link
Contributor

slozier commented Sep 28, 2021

Any chance this fix will make it to the .NET 6 release?

@tannergooding
Copy link
Member

CC. @jeffhandley, this is technically fixing a regression, can we get a bar check for it? The original fix was for .NET 6 but introduced a different edge case that this now resolves.

@jeffhandley
Copy link
Member

A regression introduced in the release that was reported and fixed by external contributors passes my bar and I expect would get tactics approval for .NET 6 GA. Please go ahead and initial the port and fill out the template, @tannergooding.

@tannergooding
Copy link
Member

/backport release/6.0

@tannergooding
Copy link
Member

/backport to release/6.0

@github-actions
Copy link
Contributor

github-actions bot commented Oct 4, 2021

Started backporting to release/6.0: https://github.com/dotnet/runtime/actions/runs/1304487290

@ghost ghost locked as resolved and limited conversation to collaborators Nov 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
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.

Right shift of specific BigInteger values is producing incorrect results
5 participants