From 6708399691439108951b2042142f7bbc34b18da9 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 11 Jun 2025 10:35:28 +0200 Subject: [PATCH] Fixed large-range int64 Next --- BeefLibs/corlib/src/Random.bf | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/BeefLibs/corlib/src/Random.bf b/BeefLibs/corlib/src/Random.bf index 4937d184..29d84eb5 100644 --- a/BeefLibs/corlib/src/Random.bf +++ b/BeefLibs/corlib/src/Random.bf @@ -197,14 +197,10 @@ namespace System ==============================================================================*/ public virtual int32 Next(int32 minValue, int32 maxValue) { - if (minValue > maxValue) - { - Runtime.FatalError(); - } - Contract.EndContractBlock(); + Debug.Assert(minValue < maxValue); int64 range = (int64)maxValue - minValue; - if (range <= (int64)Int32.MaxValue) + if (range <= Int32.MaxValue) { return ((int32)(Sample() * range) + minValue); } @@ -214,22 +210,34 @@ namespace System } } + /*=====================================Next===================================== + **Returns: An int [minvalue..maxvalue) + **Arguments: minValue -- the least legal value for the Random number. + ** maxValue -- One greater than the greatest legal return value. + **Exceptions: None. + ==============================================================================*/ public virtual int64 Next(int64 minValue, int64 maxValue) { - if (minValue > maxValue) - { - Runtime.FatalError(); - } - Contract.EndContractBlock(); + Debug.Assert(minValue < maxValue); - int64 range = (int64)maxValue - minValue; - if (range <= (int64)Int32.MaxValue) + uint64 range = (uint64)(maxValue - minValue); + if (range <= Int32.MaxValue) { - return ((int32)(Sample() * range) + minValue); + return ((int64)(Sample() * range) + minValue); } else { - return (int32)((int64)(GetSampleForLargeRange() * range) + minValue); + // In order to ensure we produce equally distributed numbers we reroll the + // range of numbers that would cause unequal distribution + bool is_power_of_2(uint64 x) => x == x & (.)-(int64)x; + uint64 excludeRange = is_power_of_2(range) ? 0 : ~(uint64)0 % range + 1; + uint64 res = 0; + repeat + { + res = NextU64(); + } + while (res < excludeRange); + return minValue + (.)(res % range); } } @@ -241,21 +249,13 @@ namespace System ==============================================================================*/ public virtual int32 Next(int32 maxValue) { - if (maxValue < 0) - { - Runtime.FatalError(); - } - Contract.EndContractBlock(); + Debug.Assert(maxValue >= 0); return (.)(Sample() * maxValue); } public virtual int64 Next(int64 maxValue) { - if (maxValue < 0) - { - Runtime.FatalError(); - } - Contract.EndContractBlock(); + Debug.Assert(maxValue >= 0); return (.)(Sample() * maxValue); }