-
Notifications
You must be signed in to change notification settings - Fork 1.6k
<experimental/random> Implement randint #361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
451bcc5
7fcdf93
51d4641
2c268b5
a452143
b9cc3cd
4fa838f
408a390
ecef960
dc7c56f
27a1b20
a0231a7
3c5b1a5
aa6bd67
5ffe8bf
58b5c96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // algorithm experimental header | ||
|
|
||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #pragma once | ||
| #ifndef _EXPERIMENTAL_ALGORITHM_ | ||
| #define _EXPERIMENTAL_ALGORITHM_ | ||
| #include <yvals_core.h> | ||
| #if _STL_COMPILER_PREPROCESSOR | ||
|
|
||
| #include <algorithm> | ||
| #include <experimental/random> | ||
SuperWig marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #pragma pack(push, _CRT_PACKING) | ||
| #pragma warning(push, _STL_WARNING_LEVEL) | ||
| #pragma warning(disable : _STL_DISABLED_WARNINGS) | ||
| _STL_DISABLE_CLANG_WARNINGS | ||
| #pragma push_macro("new") | ||
| #undef new | ||
|
|
||
| _STD_BEGIN | ||
| namespace experimental { | ||
| inline namespace fundamentals_v3 { | ||
|
|
||
| template <class _PopIt, class _SampleIt, class _Diff> | ||
| _SampleIt sample(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count) { | ||
| return _STD sample(_First, _Last, _Dest, _Count, _Engine()); | ||
| } | ||
|
|
||
| template <class _RanIt> | ||
| void shuffle(_RanIt _First, _RanIt _Last) { | ||
| _STD shuffle(_First, _Last, _Engine()); | ||
| } | ||
|
|
||
| } // namespace fundamentals_v3 | ||
| } // namespace experimental | ||
| _STD_END | ||
|
|
||
| #pragma pop_macro("new") | ||
| _STL_RESTORE_CLANG_WARNINGS | ||
| #pragma warning(pop) | ||
| #pragma pack(pop) | ||
|
|
||
| #endif // _STL_COMPILER_PREPROCESSOR | ||
| #endif // _EXPERIMENTAL_ALGORITHM_ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // random experimental header | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am willing to make a special exception to our non-goal of "Implementing Technical Specifications" on a case-by-case basis for this feature, given how obnoxious the lack of easy random number generation is for beginners, but I am concerned about permanently increasing our support cost, and the lack of progress for this proposal within WG21. |
||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #pragma once | ||
| #ifndef _EXPERIMENTAL_RANDOM_ | ||
| #define _EXPERIMENTAL_RANDOM_ | ||
| #include <yvals_core.h> | ||
| #if _STL_COMPILER_PREPROCESSOR | ||
|
|
||
| #include <random> | ||
|
|
||
| #pragma pack(push, _CRT_PACKING) | ||
| #pragma warning(push, _STL_WARNING_LEVEL) | ||
| #pragma warning(disable : _STL_DISABLED_WARNINGS) | ||
| _STL_DISABLE_CLANG_WARNINGS | ||
| #pragma push_macro("new") | ||
| #undef new | ||
|
|
||
| _STD_BEGIN | ||
| namespace experimental { | ||
| inline namespace fundamentals_v3 { | ||
|
|
||
| const seed_seq _Seed_engine() { | ||
| static_assert( | ||
| is_same_v<default_random_engine, mt19937>, "This code assumes that default_random_engine is mt19937"); | ||
| constexpr size_t _Nx = mt19937::state_size; | ||
| constexpr size_t _Wx = mt19937::word_size; | ||
| static_assert(_Wx % 32 == 0, "mt19937::word_size is not a multiple of 32"); | ||
| constexpr size_t _Kx = _Wx / 32; | ||
|
|
||
| uint32_t _Values[_Nx * _Kx]; | ||
| random_device _Rd; | ||
| _STD generate(_STD begin(_Values), _STD end(_Values), _STD ref(_Rd)); | ||
| return seed_seq(_STD cbegin(_Values), _STD cend(_Values)); | ||
| } | ||
|
|
||
| _NODISCARD inline default_random_engine& _Engine() { | ||
| thread_local default_random_engine _Eng(_Seed_engine()); | ||
| return _Eng; | ||
| } | ||
|
|
||
| template <class _IntType> | ||
StephanTLavavej marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _NODISCARD _IntType randint(const _IntType _Min, const _IntType _Max) { | ||
| _RNG_REQUIRE_INTTYPE(randint(), _IntType); | ||
| _STL_ASSERT(_Min <= _Max, "invalid min and max arguments for randint()"); | ||
| return uniform_int_distribution<_IntType>{_Min, _Max}(_Engine()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not correct. You are creating a new uniform_int_distribution with a given range and Call operator() on that temporary. However, the specification speaks from a thread_local instance of a uniform_int_distribution. Now I fail to see how that is possible if there are different calls to randint with different parameters. @BillyONeal might know, at least i remember him talking about rngs. In any case the initialization of the random number engines/distributions is generally rather costly.So recreating one seems Bad.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AFAIK distributions aren't costly only engines. And the engine being used is a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's not observable because uniform_int_distribution is stateless.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specifically, in our current implementation,
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It does? Huh, TIL. http://eel.is/c++draft/rand.req.dist#tab:rand.req.dist says there are only requirements on operator() if the same URBG is used successively.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's imposing the uniformity requirement. If you invoke a distribution repeatedly with different engines, then uniformity isn't guaranteed. Indeed it could not be, since I could invoke the distribution repeatedly with the same engine state. The hint that distributions are allowed to cache some random bits is the specification (and existence) of |
||
| } | ||
|
|
||
| inline void reseed() { | ||
SuperWig marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _Engine().seed(_Seed_engine()); | ||
| } | ||
SuperWig marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| inline void reseed(const default_random_engine::result_type _Value) { | ||
| _Engine().seed(_Value); | ||
| } | ||
| } // namespace fundamentals_v3 | ||
| } // namespace experimental | ||
| _STD_END | ||
|
|
||
| #pragma pop_macro("new") | ||
| _STL_RESTORE_CLANG_WARNINGS | ||
| #pragma warning(pop) | ||
| #pragma pack(pop) | ||
|
|
||
| #endif // _STL_COMPILER_PREPROCESSOR | ||
| #endif // _EXPERIMENTAL_RANDOM_ | ||
Uh oh!
There was an error while loading. Please reload this page.