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

Added GetInt32 to RandomNumberGenerator. #31243

Merged
merged 1 commit into from Jul 25, 2018

Conversation

@vcsjones
Copy link
Member

@vcsjones vcsjones commented Jul 21, 2018

Implement RNG.GetInt32.

/cc @bartonjs @GrabYourPitchforks

Fixes #30873.

@@ -96,12 +97,107 @@ public static void Fill(Span<byte> data)
RandomNumberGeneratorImplementation.FillSpan(data);
}

public static int GetInt32(int fromInclusive, int toExclusive)
{
if (fromInclusive >= toExclusive) throw new ArgumentException(SR.Argument_InvalidRandomRange);

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

Style: The throw statement should be on the next line, indented.


public static int GetInt32(int toExclusive)
{
if (toExclusive <= 0) throw new ArgumentOutOfRangeException(nameof(toExclusive), SR.ArgumentOutOfRange_NeedPosNum);

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

throw on next line. The next function happens to violate our style (rule 1, at that). If you wanted to clean it up I wouldn't mind.

Span<uint> valueResult = stackalloc uint[1];
ref uint result = ref valueResult[0];
Span<byte> valueResultBytes = MemoryMarshal.AsBytes(valueResult);
if (BitConverter.IsLittleEndian)

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

My personal style is to have a blank line before a control flow statement because I find it helps legibility. I'm just offering it out there, our style guide isn't prescriptive on this one way or another.

public static void GetInt32_FullRange()
{
int result = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
Assert.NotEqual(0, result);

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

There's a 1 in 4 billion chance this fails. If you want to assert something you should just assert it wasn't int.MaxValue

observedNumbers[number]++;
}
}
const double tollerance = 0.07;

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

typo: tolerance

foreach ((_, int occurences) in observedNumbers)
{
double percentage = occurences / (double)numbers.Length;
Assert.True(Math.Abs(expected - percentage) < tollerance, "Occured number of times within threshold.");

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

Typo: Occurred

double percentage = occurences / (double)numbers.Length;
Assert.True(Math.Abs(expected - percentage) < tollerance, "Occured number of times within threshold.");
}
}
}

This comment has been minimized.

@bartonjs

bartonjs Jul 22, 2018
Member

It would be good to see range validity test for negative bounds, and some tests with interesting-looking bounds sizes (really I want to test both the lzcnt implementation and the algorithm. Something annoying like (x, x + 0x0101) so the high bit in the mask value is technically required, but rarely valid. If you ran that 1000 times you "should" have at least one hit on the highest value, and shouldn't have value skew.)

(int.MinValue, int.MinValue + 3)
(-257, -129)
(-100, 5)
(254, 512)
...

Also, roll 1000d6, check for skew. (The existing "coinflip" test sort of does this, but it's bit-aligned in range, so it doesn't test the high value rejection vs mod bias algorithm differential)

@vcsjones
Copy link
Member Author

@vcsjones vcsjones commented Jul 22, 2018

I'm not fully sure what the failure in d243963 was. It looks like infrastructure? The most information I could glean was a workItemStatus had a failure count of 1, but the test failure count was 0.

Update: "mission control" says it was System.IO.Packaging.Tests.

@vcsjones
Copy link
Member Author

@vcsjones vcsjones commented Jul 22, 2018

@bartonjs @jkotas thank you for the (quick!) code review. I think I have addressed all feedback.


// We only want to generate as many bytes as required to satisfy the mask to not apply
// undue pressure to the underlying random number generator.
int bytesRequired = (32 + 7 - leadingZeroCount) / 8;

This comment has been minimized.

@danmosemsft

danmosemsft Jul 22, 2018
Member

Maybe comment where the 7 comes from?

@vcsjones
Copy link
Member Author

@vcsjones vcsjones commented Jul 23, 2018

Test failures look unrelated.

Fixes 30873.
@vcsjones
Copy link
Member Author

@vcsjones vcsjones commented Jul 25, 2018

@GrabYourPitchforks @bartonjs OK. Changed, rebased, squashed.

@GrabYourPitchforks GrabYourPitchforks merged commit 928873f into dotnet:master Jul 25, 2018
14 checks passed
14 checks passed
CROSS Check Build finished.
Details
Linux arm Release Build Build finished.
Details
Linux arm64 Release Build Build finished.
Details
Linux x64 Release Build Build finished.
Details
Linux-musl x64 Debug Build Build finished.
Details
NETFX x86 Release Build Build finished.
Details
OSX x64 Debug Build Build finished.
Details
Packaging All Configurations x64 Debug Build Build finished.
Details
UWP CoreCLR x64 Debug Build Build finished.
Details
UWP NETNative x86 Release Build Build finished.
Details
WIP ready for review
Details
Windows x64 Debug Build Build finished.
Details
Windows x86 Release Build Build finished.
Details
license/cla All CLA requirements met.
Details
@vcsjones vcsjones deleted the vcsjones:30873-rng-integers branch Jul 25, 2018
@karelz karelz added this to the 3.0 milestone Aug 21, 2018
@khellang
Copy link
Collaborator

@khellang khellang commented Feb 26, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

7 participants