diff --git a/src/libraries/System.Private.CoreLib/src/System/Random.cs b/src/libraries/System.Private.CoreLib/src/System/Random.cs
index 35ffb4c8e2d9cf..36907a29d50c2d 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Random.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Random.cs
@@ -190,16 +190,19 @@ public virtual void NextBytes(byte[] buffer)
/// Unlike , which returns an that is less than ,
/// NextInteger<int>() returns an in the inclusive range from zero through
/// and may return .
- /// must use a two's complement representation for signed values.
+ /// must behave as if it were a two's complement value with all values in range being representable.
///
public T NextInteger() where T : IBinaryInteger, IMinMaxValue
{
- if (T.MaxValue == T.Zero)
+ if (!T.IsPositive(T.MaxValue))
{
- return T.Zero;
- }
+ if (T.MaxValue == T.Zero)
+ {
+ return T.Zero;
+ }
- Debug.Assert(T.IsPositive(T.MaxValue));
+ throw new ArgumentOutOfRangeException(nameof(T), SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNonNegative, nameof(T.MaxValue), T.MaxValue));
+ }
int bitLength = T.MaxValue.GetShortestBitLength();
int byteCount = (bitLength + 7) >> 3;
@@ -217,17 +220,10 @@ public T NextInteger() where T : IBinaryInteger, IMinMaxValue
try
{
- while (true)
- {
- NextBytes(bytes);
- bytes[^1] &= topMask;
+ NextBytes(bytes);
+ bytes[^1] &= topMask;
- T value = T.ReadLittleEndian(bytes, isUnsigned: true);
- if (value <= T.MaxValue)
- {
- return value;
- }
- }
+ return T.ReadLittleEndian(bytes, isUnsigned: true);
}
finally
{
@@ -248,7 +244,7 @@ public T NextInteger() where T : IBinaryInteger, IMinMaxValue
/// [0, ). However, if equals zero, zero is returned.
///
/// is less than zero.
- /// must use a two's complement representation for signed values.
+ /// must behave as if it were a two's complement value with all values in range being representable.
public T NextInteger(T maxValue) where T : IBinaryInteger
{
ArgumentOutOfRangeException.ThrowIfNegative(maxValue);
@@ -268,7 +264,7 @@ public T NextInteger(T maxValue) where T : IBinaryInteger
/// equals , is returned.
///
/// is greater than .
- /// must use a two's complement representation for signed values.
+ /// must behave as if it were a two's complement value with all values in range being representable.
public T NextInteger(T minValue, T maxValue) where T : IBinaryInteger
{
if (minValue > maxValue)
@@ -276,16 +272,12 @@ public T NextInteger(T minValue, T maxValue) where T : IBinaryInteger
ThrowMinMaxValueSwapped();
}
- T range = maxValue - minValue;
-
// For signed types, subtraction may overflow when the range exceeds T.MaxValue.
// T.IsNegative(range) detects this. Fall back to full-width generation.
- if (T.IsNegative(range))
- {
- return NextBinaryIntegerFullRange(minValue, maxValue);
- }
-
- return NextBinaryIntegerInRange(range) + minValue;
+ T range = maxValue - minValue;
+ return T.IsNegative(range) ?
+ NextBinaryIntegerFullRange(minValue, maxValue) :
+ NextBinaryIntegerInRange(range) + minValue;
}
/// Generates a random value in [T.Zero, maxExclusive) where maxExclusive is non-negative.
@@ -331,12 +323,7 @@ private T NextBinaryIntegerInRange(T maxExclusive) where T : IBinaryIntegerGeneric rejection sampling for arbitrary types.
- private T NextBinaryIntegerRejectionSampling(T maxExclusive) where T : IBinaryInteger
- {
if (maxExclusive == T.Zero)
{
return T.Zero;
@@ -345,7 +332,7 @@ private T NextBinaryIntegerRejectionSampling(T maxExclusive) where T : IBinar
Debug.Assert(T.IsPositive(maxExclusive));
int bitLength = maxExclusive.GetShortestBitLength();
- int byteCount = (bitLength + 7) >> 3;
+ int byteCount = (int)(((uint)bitLength + 7) / 8);
// Compute mask for the top byte to reduce rejection rate.
int topBits = bitLength & 7;