3

我有一个带有意外输出的简单 C++ 程序:

#include<random>
#include<iostream>
#include "boost/random/mersenne_twister.hpp"
#include "boost/random/uniform_int_distribution.hpp"

int main(){
    std::cout << sizeof(std::mt19937) << std::endl;
    std::cout << sizeof(std::mt19937_64) << std::endl;
    std::cout << sizeof(boost::random::mt19937) << std::endl;
    std::cout << sizeof(boost::random::mt19937_64) << std::endl;
}

clang 和 gcc 输出

5000

2504

2504

2504

我发现有趣的是,mt19937(32bit one)的 sizeof 标准实现大约是 boost 版本的 2 倍,而 64bit 则完美匹配。

由于 MT 占用了大量空间,因此差异并不小。

同样奇怪的是,严格指定的算法的实现会有如此不同的 sizeof,我们不是在谈论 std::string 实现者可能会选择不同的 SSO 缓冲区大小......

我最好的猜测是 boost 要么有一个错误,要么它实现了一些稍微不同的 mt19937 版本,但维基百科这样说,暗示 boost 可能是正确的:

相对较大的状态缓冲区,2.5 KiB,

编辑:boost和std版本似乎都满足第1000个生成值是4123659995的要求,所以boost中似乎没有错误。

4

1 回答 1

4

这是标准定义:

mersenne_twister_engine<
    uint_fast32_t, // element of the buffer
    32,
    624,           // size of the buffer
    397, 31,
    0x9908b0df, 11,
    0xffffffff, 7,
    0x9d2c5680, 15,
    0xefc60000, 18, 1812433253>

问题是 GNUstd::uint_fast32_t在 64 位系统上选择了 64 位类型(这是一个好还是坏的选择是一个单独的讨论)。因此,如果缓冲区包含 32 位整数,则缓冲区的大小是预期的两倍。

这是 Boost 定义:

mersenne_twister_engine<
    uint32_t,
    32,
    624,
    397, 31,
    0x9908b0df, 11,
    0xffffffff, 7,
    0x9d2c5680, 15,
    0xefc60000, 18, 1812433253>

这是相同的,除了使用在所有系统上始终相同的固定宽度元素。


您可以std::mersenne_twister_engine直接使用 with std::uint_least32_telement 来解决此问题。使用此别名比使用固定别名更可取,因为它需要在所有系统上都受支持。

于 2020-08-26T16:25:39.923 回答