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;