【问题标题】:Converting a uint64_t rdtsc value to a uint32_t将 uint64_t rdtsc 值转换为 uint32_t
【发布时间】:2023-04-01 00:26:01
【问题描述】:

我有一个使用 Xorshift128PlusKey 的 RNG 函数 xorshift128plus:

/** 
        * \brief Keys for scalar xorshift128. Must be non-zero.
        * These are modified by xorshift128plus.
        */
        struct Xorshift128PlusKey
        {
            uint64_t s1;
            uint64_t s2;
        };

        /** 
        * \brief Return a new 64-bit random number.
        */
        uint64_t xorshift128plus(Xorshift128PlusKey* key);

我想使用 rdtsc(处理器时间戳)为我的 RNG 播种。问题是msvc下的__rdtsc内在函数返回一个64位无符号整数,而种子必须是一个32位无符号整数。将 rdtsc 转换为种子同时保持随机性的最佳方法是什么。转换必须尽可能快。

我无法使用 std lib 或 boost。 (用于游戏引擎)

【问题讨论】:

  • 我想“保持随机性”是相对的;您将丢失一半的信息。
  • 您希望在可以保留的时间戳中找到什么随机性?唯一模糊随机的是机器上次启动的时间(这可能根本不是随机的,例如,如果您的程序在启动时自动运行)。既然低 32 位比高位变化快得多,为什么不直接采用低 32 位呢?

标签: c++ random integer unsigned-integer rdtsc


【解决方案1】:

64 位处理器时间戳根本不是随机的,因此在将其缩小到 32 位时无需保留随机性。您可以简单地使用最不重要的 32 位作为种子。随机性是 PRNG 的责任,而不是种子的责任。

unsigned __int64 tsc = __rdtsc();
uint32_t seed = static_cast<uint32_t>(tsc & 0xFFFFFFFF);

【讨论】:

  • 或者像正常人一样写uint32_t seed = __rdtsc();,让编译器把高位丢掉。 (如果您想真正迂腐,您可能必须先将其强制转换或分配给uint64_t,以便在缩小时得到无符号溢出而不是有符号溢出。但是强制转换和ANDing 似乎毫无意义。)
  • @PeterCordes 谢谢,这里发布的代码是为了说明/教育目的而编写的。它等同于您的建议,并且优化编译器很可能会生成相同的指令。
  • 您可能还需要强制转换以避免编译器警告。
  • 是的,编译器知道如何优化这一切,事实上也这样做了。 (godbolt.org/g/t423Ts)。你是对的,如果你启用-Wall,MSVC 会发出警告,但是 MSVC 自己的头文件会用-Wall 发出警告。 gcc/clang/icc 即使使用-Wall -Wextra -Wpedantic 也不会发出警告。我通常不使用 MSVC,所以我只习惯 gcc/clang -Wall 警告。我仍然认为&amp; 0xFFFFFFFF 的可读性更差,因为您必须计算数字以确保有 8 个或更多,所以它实际上是一个空操作。省略它不会导致警告。
  • 顺便说一句,__rdtsc() 被定义为返回一个 unsigned 64 位类型,未签名,所以这从来不是问题。带有一个下划线的_rdtsc() 记录为returning signed __int64 by Intel。
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 2021-09-12
  • 2017-06-28
  • 1970-01-01
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多