This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
4014. LWG 3809 changes behavior of some existingstd::subtract_with_carry_engine
code
Section: 29.5.4.4 [rand.eng.sub] Status: WP Submitter: Matt Stephanson Opened: 2023-11-15 Last modified: 2024-11-28
Priority: 2
View all other issues in [rand.eng.sub].
View all issues with WP status.
Discussion:
Issue 3809(i) pointed out that subtract_with_carry_engine<T>
can be seeded with values from a linear_congruential_engine<T, 40014u, 0u, 2147483563u>
object, which results in narrowing when T
is less than 32 bits. Part of the resolution was to modify the LCG seed sequence as follows:
explicit subtract_with_carry_engine(result_type value);-7- Effects: Sets the values of X - r , … , X - 1 , in that order, as specified below. If X - 1 is then 0 , sets c to 1 ; otherwise sets c to 0 .
To set the values X k , first construct
e
, alinear_congruential_engine
object, as if by the following definition:linear_congruential_engine<result_typeuint_least32_t, 40014u,0u,2147483563u> e(value == 0u ? default_seed : value);Then, to set each X k , obtain new values z 0 , … , z n - 1 from n = ⌈ w / 32 ⌉ successive invocations of
e
. Set X k to ( ∑ j = 0 n - 1 z j ∙ 2 32 j ) mod m .
Inside linear_congruential_engine
, the seed is reduced modulo 2147483563, so uint_least32_t
is fine from that point on. This resolution, however, forces value
, the user-provided seed, to be truncated from result_type
to uint_least32_t
before the reduction, which generally will change the result. It also breaks the existing behavior that two seeds are equivalent if they're in the same congruence class modulo the divisor.
[2024-01-11; Reflector poll]
Set priority to 2 after reflector poll.
[2024-01-11; Jonathan comments]
More precisely, the resolution forces value
to be converted to uint_least32_t
, which doesn't necessarily truncate, and if it does truncate, it doesn't necessarily change the value. But it will truncate whenever value_type
is wider than uint_least32_t
, e.g. for 32-bit uint_least32_t
you get a different result for std::ranlux48_base(UINT_MAX + 1LL)()
. The new proposed resolution below restores the old behaviour for that type.
[2024-10-09; LWG telecon: Move to Ready]
[Wrocław 2024-11-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4964 after the wording changes applied by LWG 3809(i), which had been accepted into the working paper during the Kona 2023-11 meeting.
Modify 29.5.4.4 [rand.eng.sub] as indicated:
explicit subtract_with_carry_engine(result_type value);-7- Effects: Sets the values of X - r , … , X - 1 , in that order, as specified below. If X - 1 is then 0 , sets c to 1 ; otherwise sets c to 0 .
To set the values X k , first construct
e
, alinear_congruential_engine
object, as if by the following definition:linear_congruential_engine<uint_least32_t, 40014u,0u,2147483563u> e(value == 0u ? default_seed : static_cast<uint_least32_t>(value % 2147483563u));Then, to set each X k , obtain new values z 0 , … , z n - 1 from n = ⌈ w / 32 ⌉ successive invocations of
e
. Set X k to ( ∑ j = 0 n - 1 z j ∙ 2 32 j ) mod m .
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4