From 2b584292a5d73a3afb8d8087ef1ddf9e828db552 Mon Sep 17 00:00:00 2001 From: mirounga Date: Mon, 27 Jan 2025 12:03:22 -0800 Subject: [PATCH 1/5] Optimized divisionless implementation of minstd --- stl/inc/random | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/stl/inc/random b/stl/inc/random index 09b7418d93e..17da12daa2e 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -508,6 +508,34 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { } } +// Optimized specialization for minstd_rand0 +template <> +_NODISCARD unsigned int _Next_linear_congruential_value( + unsigned int _Prev) noexcept { + constexpr unsigned long long _All = 16807ULL; + constexpr unsigned long long _Mll = 2147483647ULL; + + auto _Next = static_cast(_Prev) * _All; + _Next = (_Next >> 31) + (_Next & _Mll); + _Next = _Next < _Mll ? _Next : _Next - _Mll; + + return static_cast(_Next); +} + +// Optimized specialization for minstd_rand +template <> +_NODISCARD unsigned int _Next_linear_congruential_value( + unsigned int _Prev) noexcept { + constexpr unsigned long long _All = 48271ULL; + constexpr unsigned long long _Mll = 2147483647ULL; + + auto _Next = static_cast(_Prev) * _All; + _Next = (_Next >> 31) + (_Next & _Mll); + _Next = _Next < _Mll ? _Next : _Next - _Mll; + + return static_cast(_Next); +} + template _NODISCARD constexpr unsigned int _Seed_seq_to_uint(_Seed_seq& _Seq) { unsigned int _Arr[4]{}; From 33dcc0a737bb02d3444fecb7810fa0915263269e Mon Sep 17 00:00:00 2001 From: mirounga Date: Tue, 28 Jan 2025 09:01:43 -0800 Subject: [PATCH 2/5] Formatting updates --- stl/inc/random | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 17da12daa2e..8c21fced5bb 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -510,10 +510,10 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // Optimized specialization for minstd_rand0 template <> -_NODISCARD unsigned int _Next_linear_congruential_value( +_NODISCARD inline unsigned int _Next_linear_congruential_value( unsigned int _Prev) noexcept { - constexpr unsigned long long _All = 16807ULL; - constexpr unsigned long long _Mll = 2147483647ULL; + constexpr unsigned long long _All = 16807ULL; + constexpr unsigned long long _Mll = 2147483647ULL; auto _Next = static_cast(_Prev) * _All; _Next = (_Next >> 31) + (_Next & _Mll); @@ -524,14 +524,14 @@ _NODISCARD unsigned int _Next_linear_congruential_value -_NODISCARD unsigned int _Next_linear_congruential_value( +_NODISCARD inline unsigned int _Next_linear_congruential_value( unsigned int _Prev) noexcept { - constexpr unsigned long long _All = 48271ULL; - constexpr unsigned long long _Mll = 2147483647ULL; + constexpr unsigned long long _All = 48271ULL; + constexpr unsigned long long _Mll = 2147483647ULL; - auto _Next = static_cast(_Prev) * _All; - _Next = (_Next >> 31) + (_Next & _Mll); - _Next = _Next < _Mll ? _Next : _Next - _Mll; + auto _Next = static_cast(_Prev) * _All; + _Next = (_Next >> 31) + (_Next & _Mll); + _Next = _Next < _Mll ? _Next : _Next - _Mll; return static_cast(_Next); } From 71652155e9ff4ab774433c49aa054ac03545242f Mon Sep 17 00:00:00 2001 From: mirounga Date: Fri, 31 Jan 2025 10:28:32 -0800 Subject: [PATCH 3/5] switched to if constexpr --- stl/inc/random | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 8c21fced5bb..686578f05fc 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -490,6 +490,16 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // numeric_limits::max() plus 1." That is: Just do the multiply // and let normal unsigned modulo take care of it return static_cast<_Uint>(static_cast<_Uint>(_Ax * _Prev) + _Cx); + } else if constexpr (_Cx == 0 && _Mx == 2147483647) { + // minstd_rand + constexpr unsigned long long _All = static_cast(_Ax); + constexpr unsigned long long _Mll = static_cast(_Mx); + + auto _Mul = static_cast(_Prev) * _All; + _Mul = (_Mul >> 31) + (_Mul & _Mll); + _Mul = _Mul < _Mll ? _Mul : _Mul - _Mll; + + return static_cast<_Uint>(_Mul); } else if constexpr (_Cx <= UINT_MAX && static_cast<_Uint>(_Mx - 1) <= (UINT_MAX - _Cx) / _Ax) { // unsigned int is sufficient to store intermediate calculation const auto _Mul = @@ -508,34 +518,6 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { } } -// Optimized specialization for minstd_rand0 -template <> -_NODISCARD inline unsigned int _Next_linear_congruential_value( - unsigned int _Prev) noexcept { - constexpr unsigned long long _All = 16807ULL; - constexpr unsigned long long _Mll = 2147483647ULL; - - auto _Next = static_cast(_Prev) * _All; - _Next = (_Next >> 31) + (_Next & _Mll); - _Next = _Next < _Mll ? _Next : _Next - _Mll; - - return static_cast(_Next); -} - -// Optimized specialization for minstd_rand -template <> -_NODISCARD inline unsigned int _Next_linear_congruential_value( - unsigned int _Prev) noexcept { - constexpr unsigned long long _All = 48271ULL; - constexpr unsigned long long _Mll = 2147483647ULL; - - auto _Next = static_cast(_Prev) * _All; - _Next = (_Next >> 31) + (_Next & _Mll); - _Next = _Next < _Mll ? _Next : _Next - _Mll; - - return static_cast(_Next); -} - template _NODISCARD constexpr unsigned int _Seed_seq_to_uint(_Seed_seq& _Seq) { unsigned int _Arr[4]{}; From 468a296889860f5f2e57f241ac6fde31de87788f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 3 Mar 2025 12:43:32 -0800 Subject: [PATCH 4/5] We don't need to widen `_Ax` and `_Mx`. --- stl/inc/random | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/stl/inc/random b/stl/inc/random index 686578f05fc..a8497f367ee 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -492,12 +492,9 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { return static_cast<_Uint>(static_cast<_Uint>(_Ax * _Prev) + _Cx); } else if constexpr (_Cx == 0 && _Mx == 2147483647) { // minstd_rand - constexpr unsigned long long _All = static_cast(_Ax); - constexpr unsigned long long _Mll = static_cast(_Mx); - - auto _Mul = static_cast(_Prev) * _All; - _Mul = (_Mul >> 31) + (_Mul & _Mll); - _Mul = _Mul < _Mll ? _Mul : _Mul - _Mll; + auto _Mul = static_cast(_Prev) * _Ax; + _Mul = (_Mul >> 31) + (_Mul & _Mx); + _Mul = _Mul < _Mx ? _Mul : _Mul - _Mx; return static_cast<_Uint>(_Mul); } else if constexpr (_Cx <= UINT_MAX && static_cast<_Uint>(_Mx - 1) <= (UINT_MAX - _Cx) / _Ax) { From 7b0905f0bdcbfddd2b4887ac36534546f3f56de2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 3 Mar 2025 13:08:00 -0800 Subject: [PATCH 5/5] Expand comment. --- stl/inc/random | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/random b/stl/inc/random index a8497f367ee..77726564f94 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -491,7 +491,7 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // and let normal unsigned modulo take care of it return static_cast<_Uint>(static_cast<_Uint>(_Ax * _Prev) + _Cx); } else if constexpr (_Cx == 0 && _Mx == 2147483647) { - // minstd_rand + // for minstd_rand and minstd_rand0 we can improve performance by avoiding constant divisions auto _Mul = static_cast(_Prev) * _Ax; _Mul = (_Mul >> 31) + (_Mul & _Mx); _Mul = _Mul < _Mx ? _Mul : _Mul - _Mx;