我目前正在用C++开发我自己的Mersenne Twister实现。该算法涉及多次调用以下函数:
void twistIteration(uint32_t i)
{
uint32_t x = (mt[i] & MASK_UPPER) + (mt[(i + 1) % N] & MASK_LOWER);
uint32_t xA = x >> 1;
if (x & 1)
{
xA ^= A;
}
mt[i] = mt[(i + M) % N] ^ xA;
}请注意,N、M和MASK_UPPER是模板参数,因此它们在编译时是已知的。我在另一个函数中调用此函数:
void twist()
{
for (uint32_t i = 0; i < N; i++)
{
twistIteration(i);
}
index = 0;
}在我的机器上,使用此算法生成128.000.000随机数大约需要0.95秒。然而,我找到了一种方法,通过稍微更改twist函数来显着提高算法的速度:
void twist()
{
for (uint32_t i = 0; i < N - 1; i++)
{
twistIteration(i);
}
twistIteration(N - 1);
index = 0;
}换句话说,我展开了循环的最后一次迭代,以便可以在编译时计算表达式(i + 1) % N和(i + M) % N。同样数量的随机数现在只需要0,60秒,这是一个巨大的改进。我的问题是:为什么编译器不为我做这件事?我使用默认的VS2017发布模式进行编译,并将“快速代码优化但代码更大”设置为true。有没有我遗漏的标志,或者这只是Visual Studio编译器的一些奇怪的行为?
发布于 2017-07-11 06:47:37
依赖于编译器优化来处理这样的事情可能会很棘手。最好的办法是尝试不同的标志,看看是否可以得到明显的差异。
也就是说,我会尝试显著增加您生成的元素的数量。这0.35秒很可能只是一个方差,可能取决于各种其他因素。尝试对需要一分钟(或更长时间)运行的程序进行压力测试,看看差异是否仍然如此显著。
发布于 2017-07-11 08:55:38
它可能会拒绝展开更大的循环,即使有这样的设置。
template<std::size_t...Is>
inline auto index_over(std::index_sequence<Is...>){
return [](auto&&f)->decltype(auto){
return decltype(f)(f)(std::integral_constant<std::size_t,Is>{}...);
}
}
template<std::size_t N>
inline auto index_upto(std::integral_constant<std::size_t,N> ={}){
return index_over(std::make_index_sequence<N>{});
}
template<class F>
inline auto foreacher(F&&f){
return [&](auto&&...args){
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
}现在
auto index=index_upto<N>();
index(foreacher([&](auto I){
twistIteration(I);
));强制循环展开到疯狂程度(这将需要一个聪明的编译器来重新循环)。
对于电话中的任何打字错误,我深表歉意。你可以在谷歌上搜索site:stackoverflow.com yakk和index_upto,以找到拼写错误可能更少的变体。
https://stackoverflow.com/questions/45022704
复制相似问题