Added GetInt32 to RandomNumberGenerator. #31243
Conversation
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
@@ -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); |
bartonjs
Jul 22, 2018
Member
Style: The throw statement should be on the next line, indented.
Style: The throw statement should be on the next line, indented.
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
|
||
public static int GetInt32(int toExclusive) | ||
{ | ||
if (toExclusive <= 0) throw new ArgumentOutOfRangeException(nameof(toExclusive), SR.ArgumentOutOfRange_NeedPosNum); |
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.
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) |
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.
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); |
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
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; |
bartonjs
Jul 22, 2018
Member
typo: tolerance
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."); |
bartonjs
Jul 22, 2018
Member
Typo: Occurred
Typo: Occurred
double percentage = occurences / (double)numbers.Length; | ||
Assert.True(Math.Abs(expected - percentage) < tollerance, "Occured number of times within threshold."); | ||
} | ||
} | ||
} |
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)
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)
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
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. |
|
||
// 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; |
danmosemsft
Jul 22, 2018
Member
Maybe comment where the 7 comes from?
Maybe comment where the 7 comes from?
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...phy.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
Test failures look unrelated. |
Fixes 30873.
@GrabYourPitchforks @bartonjs OK. Changed, rebased, squashed. |
928873f
into
dotnet:master
Implement RNG.GetInt32.
/cc @bartonjs @GrabYourPitchforks
Fixes #30873.