Opened 10 years ago

Last modified 10 years ago

#7951 closed Bugs

ranlux24_base(0) should be equal to ranlux24_base() — at Version 1

Reported by: Stephan T. Lavavej <stl@…> Owned by: No-Maintainer
Milestone: Boost 1.54.0 Component: random
Version: Boost 1.52.0 Severity: Problem
Keywords: Cc:

Description (last modified by Marshall Clow)

After fixing a bug in VC11's <random> (see [1]), I compared VC's fixed output to Boost 1.52.0's output and I believe I found a bug in Boost. Here's a self-contained test case:

C:\Temp>type meow.cpp
#include <ios>
#include <iostream>

#ifdef USE_BOOST
    #include <boost/random.hpp>
    using std::boolalpha;
    using std::cout;
    using std::endl;
    using boost::random::minstd_rand0;
    using boost::random::mt19937;
    using boost::random::ranlux24_base;
#else
    #include <random>
    using namespace std;
#endif

template <typename Engine> typename Engine::result_type run_10k(Engine engine) {
    for (int i = 0; i < 9999; ++i) {
        engine();
    }

    return engine();
}

int main() {
    cout << boolalpha;

    #ifdef USE_BOOST
        cout << "Using boost." << endl;
    #else
        cout << "Using std." << endl;
    #endif

    cout << "N3485 26.5.5 [rand.predef]/1 satisfied: " << (run_10k( minstd_rand0()) == 1043618065) << endl;
    cout << "N3485 26.5.5 [rand.predef]/3 satisfied: " << (run_10k(      mt19937()) == 4123659995) << endl;
    cout << "N3485 26.5.5 [rand.predef]/5 satisfied: " << (run_10k(ranlux24_base()) == 7937952   ) << endl;

    cout << "I believe  minstd_rand0(0) ==  minstd_rand0() should be  true: "
                    << (minstd_rand0(0) ==  minstd_rand0()) << endl;
    cout << "I believe       mt19937(0) ==       mt19937() should be false: "
                         << (mt19937(0) ==       mt19937()) << endl;
    cout << "I believe ranlux24_base(0) == ranlux24_base() should be  true: "
                   << (ranlux24_base(0) == ranlux24_base()) << endl;

    cout << "run_10k( minstd_rand0(0)): " << run_10k( minstd_rand0(0)) << endl;
    cout << "run_10k(      mt19937(0)): " << run_10k(      mt19937(0)) << endl;
    cout << "run_10k(ranlux24_base(0)): " << run_10k(ranlux24_base(0)) << endl;
}

With my fixed build of Milan/VC12, I'm getting:

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
meow.cpp

C:\Temp>meow
Using std.
N3485 26.5.5 [rand.predef]/1 satisfied: true
N3485 26.5.5 [rand.predef]/3 satisfied: true
N3485 26.5.5 [rand.predef]/5 satisfied: true
I believe  minstd_rand0(0) ==  minstd_rand0() should be  true: true
I believe       mt19937(0) ==       mt19937() should be false: false
I believe ranlux24_base(0) == ranlux24_base() should be  true: true
run_10k( minstd_rand0(0)): 1043618065
run_10k(      mt19937(0)): 1543171712
run_10k(ranlux24_base(0)): 7937952

(Note that VC11 RTM/Update 1 will suffer the bug described by [1].)

If I use Boost's implementation with VC11 Update 1, I get:

C:\Temp>cl /EHsc /nologo /W4 /MTd /DUSE_BOOST meow.cpp /I boost-1.52.0\include
meow.cpp

C:\Temp>meow
Using boost.
N3485 26.5.5 [rand.predef]/1 satisfied: true
N3485 26.5.5 [rand.predef]/3 satisfied: true
N3485 26.5.5 [rand.predef]/5 satisfied: true
I believe  minstd_rand0(0) ==  minstd_rand0() should be  true: true
I believe       mt19937(0) ==       mt19937() should be false: false
I believe ranlux24_base(0) == ranlux24_base() should be  true: false
run_10k( minstd_rand0(0)): 1043618065
run_10k(      mt19937(0)): 1543171712
run_10k(ranlux24_base(0)): 14007167

Here's why I believe that ranlux24_base(0) should be equal to ranlux24_base(). ranlux24_base is a subtract_with_carry_engine. 26.5.3.3 [rand.eng.sub]/7 says:

"explicit subtract_with_carry_engine(result_type value = default_seed); [...] linear_congruential_engine<result_type, 40014u,0u,2147483563u> e(value == 0u ? default_seed : value);"

/7 doesn't refer to "value" anywhere else. Therefore, 0 should behave identically to the default_seed 19780503u.

(For comparison, VC and Boost agree that minstd_rand0(0) == minstd_rand0(). 26.5.3.1 [rand.eng.lcong]/5 says:

"explicit linear_congruential_engine(result_type s = default_seed); [...] If c mod m is 0 and s mod m is 0, sets the engine's state to 1, otherwise sets the engine's state to s mod m."

The default_seed is 1u and minstd_rand0 sets c to 0, so that's why 0 behaves identically to the default_seed.)

[1] http://connect.microsoft.com/VisualStudio/feedback/details/776456

Change History (1)

comment:1 by Marshall Clow, 10 years ago

Description: modified (diff)

Fixed the formatting in the description.

Also, I verified the same behavior occurs with clang/libc++

Note: See TracTickets for help on using tickets.